我如何创建一个for循环或一个列表推导式,以便每次迭代都给我两个元素?

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

for i,k in ???:
    print str(i), '+', str(k), '=', str(i+k)

输出:

1+2=3
3+4=7
5+6=11

当前回答

for (i, k) in zip(l[::2], l[1::2]):
    print i, "+", k, "=", i+k

Zip (*iterable)返回一个元组,其中包含每个迭代对象的下一个元素。

L[::2]返回列表的第1、3、5等元素:第一个冒号表示切片从开头开始,因为后面没有数字,第二个冒号只在你想要“切片中的步骤”(在本例中是2)时才需要。

L[1::2]做同样的事情,但从列表的第二个元素开始,因此它返回原始列表的第2、第4、第6等元素。

其他回答

虽然使用zip的所有答案都是正确的,但我发现自己实现功能会导致更可读的代码:

def pairwise(it):
    it = iter(it)
    while True:
        try:
            yield next(it), next(it)
        except StopIteration:
            # no more elements in the iterator
            return

it = iter(it)部分确保它实际上是一个迭代器,而不仅仅是一个可迭代对象。如果它已经是一个迭代器,这一行是一个无操作。

用法:

for a, b in pairwise([0, 1, 2, 3, 4, 5]):
    print(a + b)

我认为这是一个分享我对n>2的概括的好地方,它只是一个可迭代对象上的滑动窗口:

def sliding_window(iterable, n):
    its = [ itertools.islice(iter, i, None) 
            for i, iter
            in enumerate(itertools.tee(iterable, n)) ]                               

    return itertools.izip(*its)

我需要把一个列表除以一个数字,然后像这样固定。

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

def divideByN(data, n):
        return [data[i*n : (i+1)*n] for i in range(len(data)//n)]  

>>> print(divideByN(l,2))
[[1, 2], [3, 4], [5, 6]]

>>> print(divideByN(l,3))
[[1, 2, 3], [4, 5, 6]]
for (i, k) in zip(l[::2], l[1::2]):
    print i, "+", k, "=", i+k

Zip (*iterable)返回一个元组,其中包含每个迭代对象的下一个元素。

L[::2]返回列表的第1、3、5等元素:第一个冒号表示切片从开头开始,因为后面没有数字,第二个冒号只在你想要“切片中的步骤”(在本例中是2)时才需要。

L[1::2]做同样的事情,但从列表的第二个元素开始,因此它返回原始列表的第2、第4、第6等元素。

如果您对性能感兴趣,我做了一个小的基准测试(使用我的库simple_benchmark)来比较解决方案的性能,并且我包含了一个来自我的包的函数:iteration_utilities.grouper

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)

所以,如果你想要一个没有外部依赖的最快的解决方案,你可能应该使用Johnysweb给出的方法(在撰写本文时,它是得到最多好评和接受的答案)。

如果您不介意额外的依赖关系,那么来自iteration_utilities的grouper可能会更快一些。

额外的想法

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

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

然后Johnysweb还提供了一个解决方案,它适用于其他大于2的大小,而其他答案则不适用(好吧,iteration_utilities。Grouper还允许将元素的数量设置为“group”)。

然后还有一个问题,如果列表中有奇数个元素,会发生什么。剩余的项目是否应该取消?是否应该填充列表以使其大小相等?剩余的物品是否要单独退回?其他答案没有直接解决这一点,但是如果我没有忽略任何东西,他们都遵循剩余的项目应该被驳回的方法(除了taskinoors的答案-这实际上会引发一个异常)。

对于石斑鱼,你可以决定你想做什么:

>>> 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)]