Pythonic是否與Ruby的#each_cons
相同?Python等效於Ruby的#each_cons?
在Ruby中,你可以這樣做:
array = [1,2,3,4]
array.each_cons(2).to_a
=> [[1,2],[2,3],[3,4]]
Pythonic是否與Ruby的#each_cons
相同?Python等效於Ruby的#each_cons?
在Ruby中,你可以這樣做:
array = [1,2,3,4]
array.each_cons(2).to_a
=> [[1,2],[2,3],[3,4]]
對於這樣的事情,itertools
是你應該尋找在模塊:
from itertools import tee, izip
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
然後:
>>> list(pairwise([1, 2, 3, 4]))
[(1, 2), (2, 3), (3, 4)]
對於更普遍的解決方案,請考慮:
def split_subsequences(iterable, length=2, overlap=0):
it = iter(iterable)
results = list(itertools.islice(it, length))
while len(results) == length:
yield results
results = results[length - overlap:]
results.extend(itertools.islice(it, length - overlap))
if results:
yield results
這允許任意長度的子序列和任意重疊。用法:
>> list(split_subsequences([1, 2, 3, 4], length=2))
[[1, 2], [3, 4]]
>> list(split_subsequences([1, 2, 3, 4], length=2, overlap=1))
[[1, 2], [2, 3], [3, 4], [4]]
的Python 3:http://docs.python.org/py3k/library/itertools.html - 的Py2:http://docs.python.org/library/itertools.html – 2011-05-04 05:22:24
這裏的一般解決方案不會表現得像'each_cons '當你有一個長度不足的序列時(each_cons返回nil)。在snipsnipsnip的答案中的實現似乎更適合於這方面。 – elias 2014-01-11 21:47:28
一個快速班輪:
a = [1, 2, 3, 4]
out = [a[i:i + 2] for i in range(len(a) - 1)]
我不認爲這是一個,我通過看內置模塊itertools
,這是我希望它是。你可以簡單地創建一個:
def each_cons(x, size):
return [x[i:i+size] for i in range(len(x)-size+1)]
Python肯定可以做到這一點。如果你不想這麼熱切地使用itertool的islice和izip。此外,重要的是要記住正常的切片將創建一個副本,所以如果內存使用很重要,你還應該考慮itertool等價物。
each_cons = lambda l: zip(l[:-1], l[1:])
我對名單的解決方案:
import itertools
def each_cons(xs, n):
return itertools.izip(*(xs[i:] for i in xrange(n)))
很好的解決方案,謝謝! =) – elias 2013-12-16 17:00:16
如果參數xs是一個生成器,則此解決方案不起作用,而且由於slice'xs [i:]',它不是非常懶惰。 – elias 2014-01-12 14:02:10
你說得對,我可以寫'islice(xs,i,None)'而不是'xs [i:]'。由於某種原因,我更喜歡後者:a)問題與列表有關。 B)[I用於列表大部分時間'each_cons'](http://c2.com/cgi/wiki?PrematureGeneralization)。 c)如'xs'是一個列表,切片列表將具有共享存儲器,所以它可能是存儲器比做得懶高效。 – snipsnipsnip 2014-01-12 17:50:57
UPDATE:沒關係我的回答如下,只是用toolz.itertoolz.sliding_window()
- 它會做正確的事情。
對於一個真正的懶惰實現,它保留了Ruby的each_cons
的行爲時,順序/發電機具有足夠的長度:
import itertools
def each_cons(sequence, n):
return itertools.izip(*(itertools.islice(g, i, None)
for i, g in
enumerate(itertools.tee(sequence, n))))
例子:
>>> print(list(each_cons(xrange(5), 2)))
[(0, 1), (1, 2), (2, 3), (3, 4)]
>>> print(list(each_cons(xrange(5), 5)))
[(0, 1, 2, 3, 4)]
>>> print(list(each_cons(xrange(5), 6)))
[]
>>> print(list(each_cons((a for a in xrange(5)), 2)))
[(0, 1), (1, 2), (2, 3), (3, 4)]
注意拆包使用的元組對於izip的參數應用於由itertools.tee(xs, n)
(即「窗口大小」)產生的大小爲n
的元組,而不是我們想要迭代的序列。
同埃利亞斯的代碼,但適用於Python 2和3:
try:
from itertools import izip # python 2
except ImportError:
from builtins import zip as izip # python 3
from itertools import islice, tee
def each_cons(sequence, n):
return izip(
*(
islice(g, i, None)
for i, g in
enumerate(tee(sequence, n))
)
)
爲什麼你需要做到這一點?只是想知道;) – Blender 2011-05-04 04:12:37
我正在做一個列表的移動平均線。 #each_cons是我在Ruby中如何做的,所以我想知道Pythonistas是如何做到的。 – maxhawkins 2011-05-04 04:38:08
對於真正相當於Ruby的each_cons,請使用['toolz.itertoolz.sliding_window()'](http://toolz.readthedocs.org/en/latest/_modules/toolz/itertoolz.html#sliding_window)。 – elias 2015-04-19 00:03:32