Python迭代器没有按预期工作
Posted
技术标签:
【中文标题】Python迭代器没有按预期工作【英文标题】:Python iterator not working as anticipated 【发布时间】:2015-07-10 20:50:44 【问题描述】:我有以下代码,我正在尝试比较一些值并返回最高值:
def high(it):
it = iter(it)
returnlist = []
try:
while True:
one = next(it)
two = next(it)
three = next(it)
if three <= two and one <= two:
returnlist.append(two)
except StopIteration:
pass
return returnlist
它工作了一半,但不正常:
>>high([0,1,-1,3,8,4,3,5,4,3,8]) #(this works)
[1, 8, 5]
>>high([5,2,4,9,6,1,3,8,0,7]) #(this doesn't work, should return [9,8]
[8]
>>high(int(is_prime(p)) for p in irange(1,20)) #(doesn't work, returns four 1's - should return 5)
[1, 1, 1, 1]
【问题讨论】:
second
未在您的行中定义return list.append(second)
我假设它是two
而不是second
单步执行你脑海中的代码,你会发现问题所在。
请记住,在循环的每次迭代中,迭代器都会前进三个位置。所以你只是在比较元素 [0,1,2]、[3,4,5]、[6,7,8] 等,而不是每组相邻的 3。
您正在做的事情可以由for one, two, three in zip(it, it, it):
完成。如果您需要遍历窗口而不是块,则需要以某种方式跟踪最后两个值,无论是显式还是其他方式。 (itertools
文档中的 pairwise
配方演示了一种简单的隐式方法。)
@heinst 你是对的!改了,谢谢:-)
【参考方案1】:
您的代码正在做的是将“列表”分成 3 个块,并且只比较每个块中的数字。这意味着您仅将前 3 个数字相互比较,然后将接下来的 3 个数字相互比较。您要做的是使用滑动窗口,以便将每个数字与旁边的数字进行比较。您可以通过跟踪以前的值来做到这一点:
def high(lst):
returnlist = []
one = None
two = None
for three in lst:
# If one is None here we haven't
# reached the first set of numbers yet
if not one is None:
if three <= two and one <= two:
returnlist.append(two)
# Update the sliding window
one = two
two = three
return returnlist
【讨论】:
这绝对是我更喜欢的方法,但是,它会导致这个实例出现问题:high(int(is_prime(p)) for p in irange(1,20))
应该等于 [1, 1, 1, 1, 1, 1]
但返回 [1, 1, 1, 1, 0, 1, 1, 0, 1, 1]
- 你认为这可能是因为一些相等错误?
我不知道你从哪里得到 is_prime
和 irange
方法,所以我无法为你测试这个案例
@unicornication 请参阅我回答的最后一段。我认为您的期望不正确,Raniz 解决方案正确返回
@Raniz 这是一个很好的解决方案,但是如果列表中可以有 None
值,则会出现错误。最好使用next
before 循环初始化前三个值。【参考方案2】:
@Shashank 评论是正确的,因为您假设迭代器是独立的,而实际上它们不是。您可以使用tee
修补您的功能:
from itertools import tee
def high(it):
it1,it2,it3 = tee(iter(it), 3)
next(it2, None)
next(it3, None); next(it3, None)
returnlist = []
try:
while True:
one = next(it1)
two = next(it2)
three = next(it3)
if three <= two and one <= two:
returnlist.append(two)
except StopIteration:
pass
return returnlist
我认为实现相同想法的更 Pythonic 方式:
from itertools import tee, izip
def threesome(iterable):
"s -> (s0,s1,s2), (s1,s2,s3), (s2,s3,s4), ..."
a, b, c = tee(iterable, 3)
next(b, None)
next(c, None); next(c, None)
return izip(a, b, c)
def high(it):
return [x2 for x1, x2, x3 in threesome(it) if x2 == max(x1, x2, x3)]
顺便说一句,我认为您对最后一种情况的预期输出不正确。您还应该在输出中看到零,因为只要您连续有三个合数(例如 8、9、10 将满足您的条件),就会发生这种情况。
【讨论】:
以上是关于Python迭代器没有按预期工作的主要内容,如果未能解决你的问题,请参考以下文章