<p>我一直在考虑如何以更好的方式解决这个问题,不需要所有的反转和索引之类的东西,我想出了一个解决方案,它更长、更复杂,但更容易阅读,更漂亮,更易于维护和扩展,IMHO。在</p>
<p>首先,我们需要一种特殊类型的列表,我们可以“正确地”迭代该列表,即使其中的一项被删除。<a href="http://www.shutupandship.com/2012/01/understanding-python-iterables-and.html" rel="nofollow noreferrer">Here</a>是一篇关于列表和迭代器是如何工作的更详细的博客文章,阅读它将帮助您理解这里发生的事情:</p>
<pre><code>class SmartList(list):
def __init__(self, *args, **kwargs):
super(SmartList, self).__init__(*args, **kwargs)
self.iterators = []
def __iter__(self):
return SmartListIter(self)
def __delitem__(self, index):
super(SmartList, self).__delitem__(index)
for iterator in self.iterators:
iterator.item_deleted(index)
</code></pre>
<p>我们扩展了内置的<code>list</code>,并使其返回一个自定义迭代器,而不是默认值。每当删除列表中的项目时,我们调用<code>self.iterators</code>列表中每个项目的<code>item_deleted</code>方法。以下是<code>SmartListIter</code>的代码:</p>
^{pr2}$
<p>因此迭代器将自己添加到迭代器列表中,并在完成后从同一列表中删除自己。如果一个索引小于当前索引的项被删除,我们将当前索引减少一个,这样就不会像普通列表迭代器那样跳过一个项。在</p>
<p><code>next</code>方法返回一个元组<code>(index, item)</code>,而不仅仅是项,因为当使用这些类时,我们就不必再费心于<code>enumerate</code>了,这使得事情变得更简单。在</p>
<p>所以这应该考虑到必须向后退,但是我们仍然需要使用很多索引来处理每个循环中的四个不同的行。既然两条线和两条线是连在一起的,那我们就来上课吧:</p>
<pre><code>class LinePair(object):
def __init__(self, pair):
self.pair = pair
self.sets = [set(line.split()) for line in pair]
self.c = len(self.sets[0]) * len(self.sets[1])
def overlap(self, other):
ab = float(len(self.sets[0] & other.sets[0]) * \
len(self.sets[1] & other.sets[1]))
overlap = ab / (self.c + other.c - ab)
return overlap
def __str__(self):
return "".join(self.pair)
</code></pre>
<p><code>pair</code>属性是一个由两行组成的元组,直接从输入文件读取,并用新行完成。我们稍后使用它将该对写回一个文件。我们还将这两条线转换为一个集合,并计算<code>c</code>属性,这是每对线的属性。最后,我们提出了一种计算一对线与另一对线之间重叠的方法。注意,<code>d</code>不见了,因为这只是另一对的<code>c</code>属性。在</p>
<p>现在是大结局:</p>
<pre><code>from itertools import izip
with open("iuputfile.txt") as fileobj:
pairs = SmartList([LinePair(pair) for pair in izip(fileobj, fileobj)])
for first_index, first_pair in pairs:
for second_index, second_pair in SmartListIter(pairs, first_index + 1):
if first_pair.overlap(second_pair) > 0.25:
del pairs[second_index]
with open("outputfile.txt", "w") as fileobj:
for index, pair in pairs:
fileobj.write(str(pair))
</code></pre>
<p>请注意,在这里读取中心循环是多么容易,它有多短。如果将来需要更改此算法,则使用此代码可能比使用其他代码更容易完成。<code>izip</code>用于分组输入文件的两行和两行,如<a href="https://stackoverflow.com/questions/2233204/how-does-zipitersn-work-in-python">here</a>所述。在</p>