我正在尝试使用NLTK的短语代码(https://github.com/nltk/nltk/blob/develop/nltk/tokenize/texttiling.py)。
它是根据文档内容将文档输入分割成几个图块的代码。我注意到,通过将整个文本作为一个图块返回,平铺对于某些文档根本不起作用,并且发现这部分代码工作很奇怪。
depth_tuples = sorted(zip(depth_scores, range(len(depth_scores))))
depth_tuples.reverse()
hp = filter(lambda x:x[0]>cutoff, depth_tuples)
for dt in hp:
boundaries[dt[1]] = 1
for dt2 in hp: #undo if there is a boundary close already
if dt[1] != dt2[1] and abs(dt2[1]-dt[1]) < 4 \
and boundaries[dt2[1]] == 1:
boundaries[dt[1]] = 0
return boundaries
Depth_tuple是一个包含元组列表[(score,index)]的列表,而hp是一个过滤结果,其得分大于某个截止值。
使用嵌套循环,它为hp的每个条目分别迭代hp两次。换句话说,对于hp的每个条目,它应检查hp的所有条目的某些内容。但是我注意到在第一次迭代后没有执行第二个循环(对于hp中的dt2)。它就像dt2指针在第一个dt的hp末尾到达,并且它没有为新的迭代初始化。
为您提供此现象的简化示例, 比如x = [(0.6,3),(0.2,1),(0.5,2),(0.4,3)]
如果截止值为0.3,则hp包含[(0.6,3),(0.5,2),(0.4,3)]
所以循环应该像
当x =(0.6,3)时,第二个循环检查[(0.6,3),(0.5,2),(0.4,3)]
当x =(0.5,2)时,第二个循环再次检查[(0.6,3),(0.5,2),(0.4,3)]
但它仅在x =(0.6,3)时才这样做,而对于x的其余部分,第二个循环不会运行。
我最初怀疑迭代器已经在第二个循环中到达了hp的末尾,但是它不能解释第一个循环的hp中的迭代器如何仍然可以...
你能解释一下为什么会这样吗?谢谢!
答案 0 :(得分:5)
您正在使用Python 3,并且该配方是为Python 2编写的。在Python 2中,filter
返回list
,显然可以使用{{1}多次迭代(内部for
)。
但是在Python 3中,for dt2 in hp
将为a one-pass iterator;现在,外部hp
将消耗第一个元素,内部for
将消耗所有剩余元素;当内循环退出时,外循环找到一个空迭代器并退出。
或者,正如Python 2和3文档所述,在Python 2中for
等同于列表理解
filter(function, iterable)
并且在Python 3中,它等同于生成器表达式
[item for item in iterable if function(item)]
作为最简单的修复,将(item for item in iterable if function(item))
返回的迭代器放入filter
:
list
答案 1 :(得分:2)
我不知道为什么Dan D.删除his answer。也许它没有完全解释这个问题,但它确实提供了正确的解决方案以及您所缺少的关键信息。
假设这是Python 3,filter
返回iterator,而不是序列。迭代器只能迭代一次。迭代器知道它的当前位置&#34;,并在你要求时懒得产生值;一旦你要求所有的价值观,就没有更多的价值可以给予。所以,例如:
>>> hp = iter([1,2,3])
>>> for dt in hp:
... print(dt)
1
2
3
>>> for dt in hp:
... print(dt)
第二次,它没有打印任何内容,因为您已经使用了所有值。
同样的事情发生在嵌套循环中:
>>> for dt in hp:
... print(dt)
... for dt in hp:
... print('>', dt)
1
> 2
> 3
在通过外循环的第一次迭代中,dt
获得第一个值。然后嵌套的内部循环获取所有其余值,因此外部循环完成。
如果你想反复迭代某些东西,最简单的方法就是把它转换成一个序列:
hp = list(hp)
在某些情况下,使用tee
可能更有效和/或在概念上更清晰,但这并不适用于此处。您的代码旨在将hp
视为序列,因此只需将其作为序列。