比较列表中所有相邻元素的Pythonic方式

6
我想知道是否有更符合Python风格的方法来完成以下操作:
A = some list
i = 0
j = 1
for _ in range(1, len(A)):
    #some operation between A[i] and A[j]
    i += 1
    j += 1

我觉得这个可以/应该用不同的方式完成。有什么想法吗?
编辑:由于有些人要求具体需求,我想要一个通用的答案。也许可以检查A [i],A [j]是否在某个范围内,或者它们是否相等。或者可能我想要一个元素“滴入”的效果。越通用越好。

你需要访问列表的索引还是仅遍历元素而不使用索引就可以满足您的需求? - Tadhg McDonald-Jensen
5个回答

8
itertools中有一个很好的小技巧可以做到这一点。作为额外的奖励,它适用于任何可迭代对象,而不仅仅是序列。
from itertools import tee

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

for current, next_ in pairwise(A):
    # do something
    pass

如果你需要索引,那么只需对成对迭代器进行enumerate
for current_index, (current, next_) in enumerate(pairwise(A)):
    # do something
    pass

枚举的返回值是什么?我感到非常困惑。它是索引还是值?枚举如何知道它是索引、值还是值和下一个值? - AAI
1
@无论如何,您可以使用help(enumerate)查看枚举的帮助,其中详细介绍了枚举的工作原理。它总是产生一个序列2元组 index,element_at_index。但是,我进一步解包element_at_indexcurrentnext_(因为这是pairwise生成的)。 - Dunes

3

Zip 可以让你组合多个迭代器:

for i,j in zip(range(0,len(A)-1), range(1,len(A))):
    #some operation between A[i] and A[j]

您也可以在范围对象上使用enumerate

for i,j in enumerate(range(1,len(A)):
    #some operation between A[i] and A[j]

请注意,与其他答案不同,这个方法可以让您访问A的索引而不仅仅是项,如果您想使用任何对A[i]A[j]的赋值,则这是必需的。例如,以下是一个非常基本的冒泡排序:

A = list(range(10))
found1=True
while found1:
    found1=False
    for i,j in enumerate(range(1,len(A))):
        if A[i] < A[j]:
            A[i],A[j] = A[j],A[i]
            found1=True
print(A)

只有当您迭代A的索引时,才有可能做到这一点。


3

针对运算符'+':

A = [A[i+1]+A[i] for i in range(len(A)-1)]

概述:

A = [operation(A[i], A[i+1]) for i in range(len(A)-1)]

2
您可以做以下事情:

A = some list
for Ai, Aj in zip(A, A[1:]):
    #some operation between A[i] and A[j]

是的,但如果目的是在Ai和Aj之间执行某些操作,它似乎可以工作。 - Jacques Gaudin
不要尝试交换A[i]A[j]中的元素。 - Tadhg McDonald-Jensen
这不允许对A[i]进行赋值,因为你没有跟踪索引。 - Tadhg McDonald-Jensen
也许发布问题的人可以澄清需求。 - Jacques Gaudin
你还不必要地创建了一个副本列表(其中两个为A[:-1]),以进行迭代,这对于大型列表来说是非常昂贵的。 - Tadhg McDonald-Jensen
显示剩余2条评论

0
from itertools import islice
A1 = iter(A)
A2 = islice(A, 1, None)
for a1, a2 in zip(A1, A2):
    # do whatever with A[i], A[i+1]

islice 比使用 A[1:] 更通用,因为它可以处理迭代器(不支持下标操作)。请注意,您需要将 None 作为第三个参数传递,因为 islice(iterable, stop) 只返回迭代器的前 stop 个元素(因此得名),这与您想要的相反。当传递第三个参数时,它会将第二个参数视为起始位置而不是停止索引。

islice(iterable, start, stop[, step])  # roughly = iterable[start:stop:step]
islice(iterable, stop)                 # roughly = iterable[:stop]

请参考文档获取更多信息。
现在zip()会发出值,直到最短的迭代器(A2)用尽。因此不必担心可能的IndexError

islice(A, n) doesn't skip n items, it stops after n items. It should be changed to islice(A, 1, None) - Mohammad Jafar Mashhadi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接