Python 迭代列表中的每两个元素

Python 迭代列表中的每两个元素,python,list,Python,List,如何为循环或列表理解创建一个,以便每次迭代都提供两个元素 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 With index: 2 (0, 1) (2, 3) (4, 5) (6, 7) (8, 9) With index: 3 (0, 1, 2) (3, 4, 5) (6, 7, 8) With index: 4 (0, 1, 2,

如何为循环或列表理解创建一个
,以便每次迭代都提供两个元素

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
With index: 2
(0, 1)
(2, 3)
(4, 5)
(6, 7)
(8, 9)
With index: 3
(0, 1, 2)
(3, 4, 5)
(6, 7, 8)
With index: 4
(0, 1, 2, 3)
(4, 5, 6, 7)

您需要一个
成对()
(或
分组()
)实现

对于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)
或者,更一般地说:

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)
from itertools import izip

def groupwise(iterable, n=2):
    "s -> (s0,s1,...,sn-1), (s1,s2,...,sn), (s2,s3,...,sn+1), ..."
    t = tee(iterable, n)
    for i in range(1, n):
        for j in range(0, i):
            next(t[i], None)
    return izip(*t)
在Python3中,您可以替换为内置函数,并删除
import

值得一提的是,我发现这是非常有效的,因为它只在列表上迭代一次,并且在这个过程中不会创建任何不必要的列表

N.B:这不应与Python自身的代码混淆,正如注释中所指出的那样,Python自身的代码生成了
s->(s0,s1)、(s1,s2)、(s2,s3)…

对于那些希望在Python 3上使用mypy进行类型检查的人来说,添加的内容很少:

输入import Iterable、Tuple、TypeVar
T=类型变量(“T”)
def分组(iterable:iterable[T],n=2)->iterable[Tuple[T,…]:
“s->(s0,s1,s2,…sn-1),(sn,sn+1,sn+2,…s2n-1),…”
返回拉链(*[iter(iterable)]*n)

您需要两个元素的元组,所以

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)
其中:

  • 数据[0::2]
    意味着创建
    (索引%2==0)
  • zip(x,y)
    从相同索引元素的x和y集合创建元组集合
    • 一个简单的解决方案

      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]) l=[1,2,3,4,5,6] 对于范围内的i(0,len(l),2): 打印str(l[i]),“+”,str(l[i+1]),“=”,str(l[i]+l[i+1]))
      zip(*iterable)
      返回一个元组,其中包含每个iterable的下一个元素

      l[::2]
      返回列表的第一、第三、第五等元素:第一个冒号表示切片从开头开始,因为后面没有数字,第二个冒号仅在需要“切片中的步骤”(在本例中为2)时才需要


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

      虽然使用
      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)
      部分确保了
      it
      实际上是一个迭代器,而不仅仅是一个iterable。如果
      it
      已经是迭代器,那么这一行是no-op

      用法:

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

      我认为这是一个很好的地方来分享我对n>2的概括,它只是一个在iterable上的滑动窗口:

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

      我希望这将是一种更加优雅的方式

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

      这里我们可以使用
      alt\u elem
      方法,它可以适合您的for循环

      def alt_elem(list, index=2):
          for i, elem in enumerate(list, start=1):
              if not i % index:
                 yield tuple(list[i-index:i])
      
      
      a = range(10)
      for index in [2, 3, 4]:
          print("With index: {0}".format(index))
          for i in alt_elem(a, index):
             print(i)
      
      输出:

      1+2=3
      3+4=7
      5+6=11
      
      With index: 2
      (0, 1)
      (2, 3)
      (4, 5)
      (6, 7)
      (8, 9)
      With index: 3
      (0, 1, 2)
      (3, 4, 5)
      (6, 7, 8)
      With index: 4
      (0, 1, 2, 3)
      (4, 5, 6, 7)
      

      注意:考虑到在func中执行的操作,上述解决方案可能不太有效。

      对于任何可能有帮助的人来说,这里是一个类似问题的解决方案,但具有重叠对(而不是互斥对)

      从Python中:

      或者,更一般地说:

      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)
      
      from itertools import izip
      
      def groupwise(iterable, n=2):
          "s -> (s0,s1,...,sn-1), (s1,s2,...,sn), (s2,s3,...,sn+1), ..."
          t = tee(iterable, n)
          for i in range(1, n):
              for j in range(0, i):
                  next(t[i], None)
          return izip(*t)
      

      这个问题的标题有误导性,您似乎在寻找连续的对,但是如果您想在所有可能的对集合上迭代,那么这将起作用:

      for i,v in enumerate(items[:-1]):
              for u in items[i+1:]:
      
      你可以使用软件包


      同时使用
      zip
      iter
      命令:

      我发现使用
      iter
      的解决方案非常优雅:

      it = iter(l)
      list(zip(it, it))
      # [(1, 2), (3, 4), (5, 6)]
      
      我在地图上找到的


      要一次推广到
      N个
      元素:

      N = 2
      list(zip(*([iter(l)] * N)))
      # [(1, 2), (3, 4), (5, 6)]
      

      如果您对性能感兴趣,我做了一个小的基准测试(使用我的库)来比较解决方案的性能,并从我的一个软件包中包含了一个函数:

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

      如果您不介意额外的依赖关系,那么
      iteration\u实用程序
      中的
      grouper
      可能会快一点

      其他想法 有些方法有一些限制,这里没有讨论

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

      然后,Johnysweb还提供了一个解决方案,该解决方案适用于除2以外的其他大小,而其他答案则不适用(好的,
      iteration\u实用程序。grouper
      还允许将元素数设置为“group”)

      还有一个问题是,如果列表中有奇数个元素,应该怎么办。剩下的项目是否应该取消?是否应该对列表进行填充,使其大小均匀?是否应将剩余项目作为单个项目返回?另一个答案并没有直接解决这一点,但是如果我没有忽略任何东西,他们都会遵循这样的方法,即剩余的项目应该被忽略(Taskinor答案除外,这实际上会引发一个例外)

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

      我需要将一个列表除以一个数字,然后像这样修复

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

      这是一个简单的解决方案,它使用范围函数从元素列表中选择替代元素

      注意:这仅对偶数列表有效

      a_list = [1, 2, 3, 4, 5, 6]
      empty_list = [] 
      for i in range(0, len(a_list), 2):
          empty_list.append(a_list[i] + a_list[i + 1])   
      print(empty_list)
      # [3, 7, 11]
      

      使用键入以便可以使用静态分析工具验证数据:

      from typing import Iterator, Any, Iterable, TypeVar, Tuple
      
      T_ = TypeVar('T_')
      Pairs_Iter = Iterator[Tuple[T_, T_]]
      
      def legs(iterable: Iterator[T_]) -> Pairs_Iter:
          begin = next(iterable)
          for end in iterable:
              yield begin, end
              begin = end
      
      简单化的方法:

      [(a[i],a[i+1]) for i in range(0,len(a),2)]
      
      如果您的数组是一个数组,并且希望成对地对其进行迭代,那么这将非常有用。 要在三元组或更多元组上迭代,只需更改“range”步骤命令,例如:

      [(a[i],a[i+1],a[i+2]) for i in range(0,len(a),3)]
      
      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)]
      
      [i for i in zip(*[iter(lst)]*2)]    
      >>>[(1, 2), (3, 4), (5, 6)]
      
      (如果数组长度和步长不合适,则必须处理多余的值)

      解包:

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

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

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

      [(a[i],a[i+1],a[i+2]) for i in range(0,len(a),3)]
      
      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)]
      
      [i for i in zip(*[iter(lst)]*2)]    
      >>>[(1, 2), (3, 4), (5, 6)]
      
      再试试看
      def grouped(itr, n=2):
          itr = iter(itr)
          end = object()
          while True:
              vals = tuple(next(itr, end) for _ in range(n))
              if vals[-1] is end:
                  return
              yield vals
      
      from collections.abc import Sized
      
      def grouped(itr, n=2, /, truncate=True, fillvalue=None, strict=False, nofill=False):
          if strict:
              if isinstance(itr, Sized):
                  if len(itr) % n != 0:
                      raise ValueError(f"{len(itr)=} is not divisible by {n=}")
          itr = iter(itr)
          end = object()
          while True:
              vals = tuple(next(itr, end) for _ in range(n))
              if vals[-1] is end:
                  if vals[0] is end:
                      return
                  if strict:
                      raise ValueError("found extra stuff in iterable")
                  if nofill:
                      yield tuple(v for v in vals if v is not end)
                      return
                  if truncate:
                      return
                  yield tuple(v if v is not end else fillvalue for v in vals)
                  return
              yield vals
      
      import itertools
      
      def grouper(iterable, n, fillvalue=None):
          "Collect data into fixed-length chunks or blocks"
          # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
          args = [iter(iterable)] * n
          return itertools.zip_longest(*args, fillvalue=fillvalue)