是否有一种漂亮的Pythonic方法循环遍历列表,重新调整一对元素?最后一个元素应与第一个元素配对.
所以,例如,如果我有列表[1,2,3],我想得到以下对:
jfs*_*jfs 111
成对访问列表的Pythonic方法是:zip(L, L[1:]).要将最后一项连接到第一项:
>>> L = [1, 2, 3]
>>> zip(L, L[1:] + L[:1])
[(1, 2), (2, 3), (3, 1)]
Run Code Online (Sandbox Code Playgroud)
g.d*_*d.c 49
>>> from collections import deque
>>>
>>> l = [1,2,3]
>>> d = deque(l)
>>> d.rotate(-1)
>>> zip(l, d)
[(1, 2), (2, 3), (3, 1)]
Run Code Online (Sandbox Code Playgroud)
Tad*_*sen 44
我会对文档中的pairwise配方稍作修改:itertools
def pairwise_circle(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ... (s<last>,s0)"
a, b = itertools.tee(iterable)
first_value = next(b, None)
return itertools.zip_longest(a, b,fillvalue=first_value)
Run Code Online (Sandbox Code Playgroud)
这将只保留对第一个值的引用,当第二个迭代器耗尽时,zip_longest将使用第一个值填充最后一个位置.
(另请注意,它适用于像生成器这样的迭代器以及列表/元组之类的迭代.)
请注意,@ Barry的解决方案与此非常相似,但在我看来更容易理解,更容易扩展到一个元素之外.
Roa*_*ich 38
我会itertools.cycle搭配zip:
import itertools
def circular_pairwise(l):
second = itertools.cycle(l)
next(second)
return zip(l, second)
Run Code Online (Sandbox Code Playgroud)
cycle 返回一个iterable,它按顺序生成其参数的值,从最后一个值循环到第一个值.
我们跳过第一个值,所以它从位置开始1(而不是0).
接下来,我们zip使用原始的,未列出的列表. zip很好,因为当它的任何参数迭代都用完时它会停止.
这样做可以避免创建任何中间列表:cycle保存对原始列表的引用,但不复制它. zip以同样的方式运作.
需要注意的是,这将打破,如果输入的是一个很重要的iterator,比如file,(或map或zip在蟒蛇-3 ),如在一个地方(通过推进next(second))会自动前进迭代器中的所有其他人.这很容易使用itertools.tee,它在原始的iterable上生成两个独立运算的迭代器:
def circular_pairwise(it):
first, snd = itertools.tee(it)
second = itertools.cycle(snd)
next(second)
return zip(first, second)
Run Code Online (Sandbox Code Playgroud)
tee 可以使用大量额外的存储空间,例如,如果其中一个返回的迭代器在触摸另一个之前用完,但由于我们只有一个步骤差异,因此额外的存储空间很小.
che*_*ner 28
有更有效的方法(不构建临时列表),但我认为这是最简洁的:
> l = [1,2,3]
> zip(l, (l+l)[1:])
[(1, 2), (2, 3), (3, 1)]
Run Code Online (Sandbox Code Playgroud)
Atn*_*Atn 22
我会使用列表理解,并利用l[-1]最后一个元素的事实.
>>> l = [1,2,3]
>>> [(l[i-1],l[i]) for i in range(len(l))]
[(3, 1), (1, 2), (2, 3)]
Run Code Online (Sandbox Code Playgroud)
你不需要这样的临时列表.
Aar*_*all 22
成对循环Python'for'循环
如果你喜欢接受的答案,
zip(L, L[1:] + L[:1])
Run Code Online (Sandbox Code Playgroud)
您可以使用以下语义在语义上使用itertools以下代码获取更多内存灯:
from itertools import islice, chain #, izip as zip # uncomment if Python 2
Run Code Online (Sandbox Code Playgroud)
这几乎没有在原始列表之外的内存中实现任何内容(假设列表相对较大):
zip(l, chain(islice(l, 1, None), islice(l, None, 1)))
Run Code Online (Sandbox Code Playgroud)
要使用,只需消费(例如,使用列表):
>>> list(zip(l, chain(islice(l, 1, None), islice(l, None, 1))))
[(1, 2), (2, 3), (3, 1)]
Run Code Online (Sandbox Code Playgroud)
这可以扩展到任何宽度:
def cyclical_window(l, width=2):
return zip(*[chain(islice(l, i, None), islice(l, None, i)) for i in range(width)])
Run Code Online (Sandbox Code Playgroud)
和用法:
>>> l = [1, 2, 3, 4, 5]
>>> cyclical_window(l)
<itertools.izip object at 0x112E7D28>
>>> list(cyclical_window(l))
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 1)]
>>> list(cyclical_window(l, 4))
[(1, 2, 3, 4), (2, 3, 4, 5), (3, 4, 5, 1), (4, 5, 1, 2), (5, 1, 2, 3)]
Run Code Online (Sandbox Code Playgroud)
itertools.tee与cycle您还可以使用tee以避免创建冗余循环对象:
from itertools import cycle, tee
ic1, ic2 = tee(cycle(l))
next(ic2) # must still queue up the next item
Run Code Online (Sandbox Code Playgroud)
现在:
>>> [(next(ic1), next(ic2)) for _ in range(10)]
[(1, 2), (2, 3), (3, 1), (1, 2), (2, 3), (3, 1), (1, 2), (2, 3), (3, 1), (1, 2)]
Run Code Online (Sandbox Code Playgroud)
这是难以置信的高效率,的预期使用iter与next和优雅的使用cycle,tee和zip.
不要cycle直接传递给list你,除非你已经保存了你的工作并且有时间让你的计算机在你的内存最大化时停止运行 - 如果你很幸运,过了一段时间你的操作系统会在它崩溃你的计算机之前终止进程.
最后,没有标准的lib导入,但这仅适用于原始列表的长度(否则为IndexError.)
>>> [(l[i], l[i - len(l) + 1]) for i in range(len(l))]
[(1, 2), (2, 3), (3, 1)]
Run Code Online (Sandbox Code Playgroud)
您可以使用modulo继续:
>>> len_l = len(l)
>>> [(l[i % len_l], l[(i + 1) % len_l]) for i in range(10)]
[(1, 2), (2, 3), (3, 1), (1, 2), (2, 3), (3, 1), (1, 2), (2, 3), (3, 1), (1, 2)]
Run Code Online (Sandbox Code Playgroud)
Bar*_*rry 19
令人惊讶的是有多少种方法可以解决这个问题.
还有一个.你可以使用pairwise配方而不是拉链b,chain它与你已经弹出的第一个元素.不需要cycle的时候,我们只需要一个额外的价值:
from itertools import chain, izip, tee
def pairwise_circle(iterable):
a, b = tee(iterable)
first = next(b, None)
return izip(a, chain(b, (first,)))
Run Code Online (Sandbox Code Playgroud)
Dav*_*len 11
我喜欢不修改原始列表的解决方案,也不会将列表复制到临时存储:
def circular(a_list):
for index in range(len(a_list) - 1):
yield a_list[index], a_list[index + 1]
yield a_list[-1], a_list[0]
for x in circular([1, 2, 3]):
print x
Run Code Online (Sandbox Code Playgroud)
输出:
(1, 2)
(2, 3)
(3, 1)
Run Code Online (Sandbox Code Playgroud)
我可以想象这被用在一些非常大的内存数据中.
即使列表l占用了系统的大部分内存,这个也可以工作.(如果有什么东西可以保证这种情况不可能,那么由chepner发布的zip很好)
l.append( l[0] )
for i in range( len(l)-1):
pair = l[i],l[i+1]
# stuff involving pair
del l[-1]
Run Code Online (Sandbox Code Playgroud)
或更普遍(适用于任何偏移,n即l[ (i+n)%len(l) ])
for i in range( len(l)):
pair = l[i], l[ (i+1)%len(l) ]
# stuff
Run Code Online (Sandbox Code Playgroud)
如果你在一个具有相当快速的模数除法的系统上(即不是一些豌豆脑的嵌入式系统).
似乎有一种常见的信念,即使用整数下标对列表进行索引是非pythonic并且最好避免.为什么?
这是我的解决方案,看起来Pythonic对我来说足够了:
l = [1,2,3]
for n,v in enumerate(l):
try:
print(v,l[n+1])
except IndexError:
print(v,l[0])
Run Code Online (Sandbox Code Playgroud)
打印:
1 2
2 3
3 1
Run Code Online (Sandbox Code Playgroud)
生成器功能版本:
def f(iterable):
for n,v in enumerate(iterable):
try:
yield(v,iterable[n+1])
except IndexError:
yield(v,iterable[0])
>>> list(f([1,2,3]))
[(1, 2), (2, 3), (3, 1)]
Run Code Online (Sandbox Code Playgroud)
这个怎么样?
li = li+[li[0]]
pairwise = [(li[i],li[i+1]) for i in range(len(li)-1)]
Run Code Online (Sandbox Code Playgroud)
from itertools import izip, chain, islice
itr = izip(l, chain(islice(l, 1, None), islice(l, 1)))
Run Code Online (Sandbox Code Playgroud)
(如上所述@ jf-sebastian的"zip"答案,但使用itertools.)
注:编辑给出有用的微调从@ 200_success.以前是:
itr = izip(l, chain(l[1:], l[:1]))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5845 次 |
| 最近记录: |