迭代列表中的每两个元素

jac*_*hab 189 python list

如何进行for循环或列表理解,以便每次迭代都给出两个元素?

l = [1,2,3,4,5,6]

for i,k in ???:
    print str(i), '+', str(k), '=', str(i+k)
Run Code Online (Sandbox Code Playgroud)

输出:

1+2=3
3+4=7
5+6=11
Run Code Online (Sandbox Code Playgroud)

Joh*_*web 215

您需要一个pairwise()(或grouped())实现.

对于Python 2:

from itertools import izip

def pairwise(iterable):
    "s -> (s0, s1), (s2, s3), (s4, s5), ..."
    a = iter(iterable)
    return izip(a, a)

for x, y in pairwise(l):
   print "%d + %d = %d" % (x, y, x + y)
Run Code Online (Sandbox Code Playgroud)

或者,更一般地说:

from itertools import izip

def grouped(iterable, n):
    "s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), (s2n,s2n+1,s2n+2,...s3n-1), ..."
    return izip(*[iter(iterable)]*n)

for x, y in grouped(l, 2):
   print "%d + %d = %d" % (x, y, x + y)
Run Code Online (Sandbox Code Playgroud)

在Python 3中,您可以izip使用内置zip()函数替换,然后删除import.

所有信贷蒂诺他的回答我的问题,我发现这是因为它只有一次迭代列表非常有效,在此过程中不会产生任何不必要的名单.

:这不应该混淆的pairwise食谱 Python的自己的itertools文件,其收益率s -> (s0, s1), (s1, s2), (s2, s3), ...,如所指出的@lazyr中的注释.

  • 不要与[itertools](http://docs.python.org/library/itertools.html)食谱部分中建议的配对函数相混淆,它产生`s - >(s0,s1),(s1,s2) ),(s2,s3),......` (13认同)
  • 小心!使用这些函数会使您不会迭代迭代的最后一个元素.示例:list(分组([1,2,3],2))>>> [(1,2)] ..当你期望[(1,2),(3,)] (4认同)
  • @ Erik49:在问题中指定的情况下,拥有一个"不完整"的元组是没有意义的.如果你想包含一个不完整的元组,你可以使用`izip_longest()`而不是`izip()`.例如:`list(izip_longest(*[iter([1,2,3])]*2,fillvalue = 0))` - >`[(1,2),(3,0)]`.希望这可以帮助. (4认同)

Mar*_*gus 168

那么你需要2个元素的元组,所以

data = [1,2,3,4,5,6]
for i,k in zip(data[0::2], data[1::2]):
    print str(i), '+', str(k), '=', str(i+k)
Run Code Online (Sandbox Code Playgroud)

哪里:

  • data[0::2] 意味着创建元素的子集集合 (index % 2 == 0)
  • zip(x,y) 从x和y集合创建一个元组集合相同的索引元素.

  • 比拉入导入和定义函数更清晰! (14认同)
  • 如果需要两个以上的元素,也可以扩展.例如`for i,j,k in zip(data [0 :: 3],data [1 :: 3],data [2 :: 3]):` (7认同)
  • @kmarsh:但这只适用于序列,该函数适用于任何迭代; 这使用了O(N)额外的空间,功能没有; 另一方面,这通常更快.选择其中一个是有充分理由的; 害怕"进口"不是其中之一. (5认同)
  • @abarnert `itertools.islice` 来救援:`for i,k in zip(islice(data, 0, None, 2), islice(data, 1, None, 2):`。而且,如果你担心的话关于“不迭代可迭代的最后一个元素”,请将“zip”替换为“itertools.zip_longest”,并使用对您有意义的“fillvalue”。 (2认同)

小智 69

>>> l = [1,2,3,4,5,6]

>>> zip(l,l[1:])
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

>>> zip(l,l[1:])[::2]
[(1, 2), (3, 4), (5, 6)]

>>> [a+b for a,b in zip(l,l[1:])[::2]]
[3, 7, 11]

>>> ["%d + %d = %d" % (a,b,a+b) for a,b in zip(l,l[1:])[::2]]
['1 + 2 = 3', '3 + 4 = 7', '5 + 6 = 11']
Run Code Online (Sandbox Code Playgroud)

  • @HamidRohani`zip`在Python 3中返回一个`zip`对象,该对象不可订阅.它需要首先转换为序列(`list`,`tuple`等),但*"not working"*有点拉伸. (6认同)
  • 这不适用于 Python-3.6.0,但仍适用于 Python-2.7.10 (3认同)

tas*_*oor 55

简单的解决方案.

l = [1, 2, 3, 4, 5, 6]

for i in range(0, len(l), 2):
    print str(l[i]), '+', str(l[i + 1]), '=', str(l[i] + l[i + 1])

  • 如果您的列表不是偶数,而您只想按原样显示最后一个数字怎么办? (3认同)
  • 谢谢。我已经知道如何去做。问题是,如果您的列表中没有数字,则将出现索引错误。尝试解决它:例外: (2认同)
  • 或者生成器的“((l[i], l[i+1])for i in range(0, len(l), 2))”,可以轻松修改为更长的元组。 (2认同)

mic*_*c_e 41

虽然所有使用的答案zip都是正确的,但我发现自己实现这些功能会带来更易读的代码:

def pairwise(it):
    it = iter(it)
    while True:
        yield next(it), next(it)
Run Code Online (Sandbox Code Playgroud)

it = iter(it)部分确保它it实际上是一个迭代器,而不仅仅是一个迭代器.如果it已经是迭代器,则该行是无操作的.

用法:

for a, b in pairwise([0, 1, 2, 3, 4, 5]):
    print(a + b)
Run Code Online (Sandbox Code Playgroud)

  • 该解决方案允许将元组的大小概括为> 2 (2认同)
  • 我喜欢这样做,可以避免将内存使用量增加三倍,这是公认的答案。 (2认同)

Viv*_*san 19

为迟到而道歉.我希望这将是更优雅的做法.

a = [1,2,3,4,5,6]
zip(a[::2], a[1::2])

[(1, 2), (3, 4), (5, 6)]
Run Code Online (Sandbox Code Playgroud)

  • 小心长度奇数的列表!将省略最后一个元素 (2认同)
  • 对于奇数长度,请使用“from itertools import zip_longest”。它将返回 `[(1, 2), (3, 4), (5, 6), (7, None)]` (2认同)

MSe*_*ert 16

如果你对性能感兴趣,我做了一个小的基准来比较解决方案的性能,我从我的一个软件包中包含了一个函数: simple_benchmark

from iteration_utilities import grouper
import matplotlib as mpl
from simple_benchmark import BenchmarkBuilder

bench = BenchmarkBuilder()

@bench.add_function()
def Johnsyweb(l):
    def pairwise(iterable):
        "s -> (s0, s1), (s2, s3), (s4, s5), ..."
        a = iter(iterable)
        return zip(a, a)

    for x, y in pairwise(l):
        pass

@bench.add_function()
def Margus(data):
    for i, k in zip(data[0::2], data[1::2]):
        pass

@bench.add_function()
def pyanon(l):
    list(zip(l,l[1:]))[::2]

@bench.add_function()
def taskinoor(l):
    for i in range(0, len(l), 2):
        l[i], l[i+1]

@bench.add_function()
def mic_e(it):
    def pairwise(it):
        it = iter(it)
        while True:
            try:
                yield next(it), next(it)
            except StopIteration:
                return

    for a, b in pairwise(it):
        pass

@bench.add_function()
def MSeifert(it):
    for item1, item2 in grouper(it, 2):
        pass

bench.use_random_lists_as_arguments(sizes=[2**i for i in range(1, 20)])
benchmark_result = bench.run()
mpl.rcParams['figure.figsize'] = (8, 10)
benchmark_result.plot_both(relative_to=MSeifert)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

Windows 10 64位Anaconda Python 3.6

因此,如果您想要没有外部依赖关系的最快解决方案,您可能应该只使用Johnysweb提供的方法(在撰写本文时,它是最受欢迎和接受的答案).

如果你不介意额外的依赖,那么iteration_utilities.grouperfrom grouper可能会更快一些.

额外的想法

有些方法有一些限制,这里没有讨论过.

例如,一些解决方案仅适用于序列(即列表,字符串等),例如使用索引的Margus/pyanon/taskinoor解决方案,而其他解决方案适用于任何可迭代的(即序列生成器,迭代器),如Johnysweb/mic_e /我的解决方案.

然后Johnysweb还提供了一个解决方案,适用于2以外的其他大小,而其他答案不适用(好吧,iteration_utilities也允许将元素数量设置为"组").

然后还有一个问题是如果列表中有奇数个元素会发生什么.剩下的项目应该被解雇吗?列表是否应该填充以使其大小均匀?剩下的物品应该单独归还吗?另一个答案没有直接解决这一点,但如果我没有忽略任何事情,他们都会遵循剩下的项目应该被解雇的方法(除了taskinoors的答案 - 这实际上会引发异常).

有了iteration_utilities.grouper你可以决定你想要做什么:

>>> from iteration_utilities import grouper

>>> list(grouper([1, 2, 3], 2))  # as single
[(1, 2), (3,)]

>>> list(grouper([1, 2, 3], 2, truncate=True))  # ignored
[(1, 2)]

>>> list(grouper([1, 2, 3], 2, fillvalue=None))  # padded
[(1, 2), (3, None)]
Run Code Online (Sandbox Code Playgroud)


Qua*_*nic 11

一起使用zipiter命令:

我发现这个解决方案iter非常优雅:

it = iter(l)
list(zip(it, it))
# [(1, 2), (3, 4), (5, 6)]
Run Code Online (Sandbox Code Playgroud)

我在Python 3 zip文档中找到了它.

it = iter(l)
print(*(f'{u} + {v} = {u+v}' for u, v in zip(it, it)), sep='\n')

# 1 + 2 = 3
# 3 + 4 = 7
# 5 + 6 = 11
Run Code Online (Sandbox Code Playgroud)

一次推广N元素:

N = 2
list(zip(*([iter(l)] * N)))
# [(1, 2), (3, 4), (5, 6)]
Run Code Online (Sandbox Code Playgroud)


小智 10

有很多方法可以做到这一点。例如:

lst = [1,2,3,4,5,6]
[(lst[i], lst[i+1]) for i,_ in enumerate(lst[:-1])]    
>>>[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

list(zip(*[iter(lst)]*2))
>>>[(1, 2), (3, 4), (5, 6)]
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案被低估了。没有外部方法和管理赔率的情况。先生,为你加油。 (3认同)

ale*_*o98 9

for (i, k) in zip(l[::2], l[1::2]):
    print i, "+", k, "=", i+k
Run Code Online (Sandbox Code Playgroud)

zip(*iterable) 返回一个元组,其中包含每个iterable的下一个元素.

l[::2] 返回列表的第1个,第3个,第5个等元素:第一个冒号表示切片从头开始,因为它后面没有数字,只有你想要一个'切片中的步骤时才需要第二个冒号'(在这种情况下为2).

l[1::2]做同样的事情,但从列表的第二个元素开始,所以它返回原始列表的第2,第4,第6等元素.

  • 两年前Margus已经给出了这个答案.http://stackoverflow.com/questions/5389507/iterating-over-every-two-elements-in-a-list#answer-5389578 (4认同)

toa*_*car 6

带开箱:

l = [1,2,3,4,5,6]
while l:
    i, k, *l = l
    print(f'{i}+{k}={i+k}') 
Run Code Online (Sandbox Code Playgroud)

注意:这将消耗l,之后将其留空。