在Python中以列表(循环方式)迭代对

这个问题很简单,我想遍历列表中的每个元素和下一个成对的元素(用最后一个元素包装)。

我曾经想过两种不合理的方式:

def pairs(lst): n = len(lst) for i in range(n): yield lst[i],lst[(i+1)%n] 

和:

 def pairs(lst): return zip(lst,lst[1:]+[lst[:1]]) 

预期产出:

 >>> for i in pairs(range(10)): print i (0, 1) (1, 2) (2, 3) (3, 4) (4, 5) (5, 6) (6, 7) (7, 8) (8, 9) (9, 0) >>> 

任何关于更pythonic这样做的build议? 也许有一个预定义的function,我没有听说过?

也是更普遍的n倍(与三胞胎,四重奏,而不是对)版本可能是有趣的。

 def pairs(lst): i = iter(lst) first = prev = item = i.next() for item in i: yield prev, item prev = item yield item, first 

适用于任何非空序列,不需要索引。

我已经编码了自己的元组一般版本,我喜欢第一个简单的优雅,我越看越,Pythonic感觉对我来说…毕竟,什么是Pythonic比单线拉链,星号参数扩展,列表parsing,列表切片,列表连接和“范围”?

 def ntuples(lst, n): return zip(*[lst[i:]+lst[:i] for i in range(n)]) 

itertools版本应该足够高效,即使对于大型列表…

 from itertools import * def ntuples(lst, n): return izip(*[chain(islice(lst,i,None), islice(lst,None,i)) for i in range(n)]) 

还有一个不可索引序列的版本:

 from itertools import * def ntuples(seq, n): iseq = iter(seq) curr = head = tuple(islice(iseq, n)) for x in chain(iseq, head): yield curr curr = curr[1:] + (x,) 

无论如何,谢谢大家的build议! 🙂

我一如往常,像开球:

 from itertools import tee, izip, chain def pairs(iterable): a, b = tee(iterable) return izip(a, chain(b, [next(b)])) 

这可能是令人满意的:

 def pairs(lst): for i in range(1, len(lst)): yield lst[i-1], lst[i] yield lst[-1], lst[0] >>> a = list(range(5)) >>> for a1, a2 in pairs(a): ... print a1, a2 ... 0 1 1 2 2 3 3 4 4 0 

如果你喜欢这种东西,看看wordaligned.org上的python文章。 作者对Python中的生成器有着特别的喜爱。

我会这样做(主要是因为我可以读这个):

 class Pairs(object): def __init__(self, start): self.i = start def next(self): p, p1 = self.i, self.i + 1 self.i = p1 return p, p1 def __iter__(self): return self if __name__ == "__main__": x = Pairs(0) y = 1 while y < 20: print x.next() y += 1 

得到:

 (0, 1) (1, 2) (2, 3) (3, 4) (4, 5) (5, 6) (6, 7) (7, 8) (8, 9) 
 [(i,(i+1)%len(range(10))) for i in range(10)] 

用你想要的列表replace范围(10)。

一般来说,“循环索引”在Python中是相当容易的; 只是使用:

 a[i%len(a)] 

要回答你关于解决一般情况的问题:

 import itertools def pair(series, n): s = list(itertools.tee(series, n)) try: [ s[i].next() for i in range(1, n) for j in range(i)] except StopIteration: pass while True: result = [] try: for j, ss in enumerate(s): result.append(ss.next()) except StopIteration: if j == 0: break else: s[j] = iter(series) for ss in s[j:]: result.append(ss.next()) yield result 

输出是这样的:

 >>> for a in pair(range(10), 2): ... print a ... [0, 1] [1, 2] [2, 3] [3, 4] [4, 5] [5, 6] [6, 7] [7, 8] [8, 9] [9, 0] >>> for a in pair(range(10), 3): ... print a ... [0, 1, 2] [1, 2, 3] [2, 3, 4] [3, 4, 5] [4, 5, 6] [5, 6, 7] [6, 7, 8] [7, 8, 9] [8, 9, 0] [9, 0, 1] 

这无限循环,无论好坏,但在algorithm上非常清楚。

 from itertools import tee, cycle def nextn(iterable,n=2): ''' generator that yields a tuple of the next n items in iterable. This generator cycles infinitely ''' cycled = cycle(iterable) gens = tee(cycled,n) # advance the iterators, this is O(n^2) for (ii,g) in zip(xrange(n),gens): for jj in xrange(ii): gens[ii].next() while True: yield tuple([x.next() for x in gens]) def test(): data = ((range(10),2), (range(5),3), (list("abcdef"),4),) for (iterable, n) in data: gen = nextn(iterable,n) for j in range(len(iterable)+n): print gen.next() test() 

得到:

 (0, 1) (1, 2) (2, 3) (3, 4) (4, 5) (5, 6) (6, 7) (7, 8) (8, 9) (9, 0) (0, 1) (1, 2) (0, 1, 2) (1, 2, 3) (2, 3, 4) (3, 4, 0) (4, 0, 1) (0, 1, 2) (1, 2, 3) (2, 3, 4) ('a', 'b', 'c', 'd') ('b', 'c', 'd', 'e') ('c', 'd', 'e', 'f') ('d', 'e', 'f', 'a') ('e', 'f', 'a', 'b') ('f', 'a', 'b', 'c') ('a', 'b', 'c', 'd') ('b', 'c', 'd', 'e') ('c', 'd', 'e', 'f') ('d', 'e', 'f', 'a') 

即使是较短版本的Fortran的zip *范围解决scheme(这次使用lambda);

 group = lambda t, n: zip(*[t[i::n] for i in range(n)]) group([1, 2, 3, 3], 2) 

得到:

 [(1, 2), (3, 4)] 

这里有一个支持可选启动索引的版本(例如,返回(4,0)作为第一对,使用start = -1:

 import itertools def iterrot(lst, start = 0): if start == 0: i = iter(lst) elif start > 0: i1 = itertools.islice(lst, start, None) i2 = itertools.islice(lst, None, start) i = itertools.chain(i1, i2) else: # islice doesn't support negative slice indices so... lenl = len(lst) i1 = itertools.islice(lst, lenl + start, None) i2 = itertools.islice(lst, None, lenl + start) i = itertools.chain(i1, i2) return i def iterpairs(lst, start = 0): i = iterrot(lst, start) first = prev = i.next() for item in i: yield prev, item prev = item yield prev, first def itertrios(lst, start = 0): i = iterrot(lst, start) first = prevprev = i.next() second = prev = i.next() for item in i: yield prevprev, prev, item prevprev, prev = prev, item yield prevprev, prev, first yield prev, first, second 
 def pairs(ex_list): for i, v in enumerate(ex_list): if i < len(list) - 1: print v, ex_list[i+1] else: print v, ex_list[0] 

枚举返回一个包含索引号和值的元组。 我打印出列表ex_list[i+1]的值和下面的元素。 如果i < len(list) - 1表示如果v 不是列表的最后一个成员。 如果是:print v和列表的第一个元素print v, ex_list[0]

编辑:

你可以让它返回一个列表。 只需将打印的元组追加到列表中并返回即可。

 def pairs(ex_list): result = [] for i, v in enumerate(ex_list): if i < len(list) - 1: result.append((v, ex_list[i+1])) else: result.append((v, ex_list[0])) return result 

当然,你可以随时使用一个deque

 from collections import deque from itertools import * def pairs(lst, n=2): itlst = iter(lst) start = list(islice(itlst, 0, n-1)) deq = deque(start, n) for elt in chain(itlst, start): deq.append(elt) yield list(deq) 
 i=(range(10)) for x in len(i): print i[:2] i=i[1:]+[i[1]] 

比这更pythonic是不可能的