2010-02-09 31 views
80
s = [1,2,3,4,5,6,7,8,9] 
n = 3 

zip(*[iter(s)]*n) # returns [(1,2,3),(4,5,6),(7,8,9)] 

zip(*[iter(s)]*n)如何工作?如果使用更詳細的代碼編寫它會是什麼樣子?zip(* [iter(s)] * n)在Python中如何工作?

+1

也看看這裏它是如何工作的也解釋:http://stackoverflow.com/questions/2202461/yield-multiple-objects-at-a-time-from-an-iterable-object/2202485# 2202485 – 2010-02-09 23:22:24

+0

如果這裏的答案還不夠,我在這裏發表博文:http://telliott99.blogspot.com/2010/01/chunks-of-sequence-in-python.html – telliott99 2010-02-10 00:22:35

+5

儘管非常有趣,但這種技巧必須去對付Python的核心「可讀性」值! – Demis 2015-11-26 07:42:42

回答

82

iter()是一個序列上的迭代器。 [x] * n產生包含n數量的x的列表,即長度爲n的列表,其中每個元素是x*arg將序列解壓縮爲函數調用的參數。因此,你將相同的迭代器傳遞3次到zip(),並且每次都從迭代器中取出一個項目。

x = iter([1,2,3,4,5,6,7,8,9]) 
print zip(x, x, x) 
7

iter(s)返回s的迭代器。

[iter(s)]*n列出了n次與s相同的迭代器。

因此,在做zip(*[iter(s)]*n)時,它會從列表中的所有三個迭代器中按順序提取一個項目。由於所有的迭代器都是同一個對象,因此它只是按照n的大塊對列表進行分組。

+4

不是'相同列表的迭代器',而是'n次相同的迭代器對象'。不同的迭代器對象不共享狀態,即使它們具有相同的列表。 – 2010-02-09 23:41:28

+0

謝謝,糾正。的確,那正是我所「想」的,但寫了別的東西。 – sttwister 2010-02-10 19:44:08

37

其他很好的答案和評論很好地解釋了argument unpackingzip()的作用。

由於Ignacioujukatzel說,你傳遞給zip()三個引用到相同的迭代器和zip(),使3元組整數,爲了-從每個參考迭代器:

1,2,3,4,5,6,7,8,9 1,2,3,4,5,6,7,8,9 1,2,3,4,5,6,7,8,9 
^     ^    ^   
    ^    ^    ^
      ^    ^    ^

而且因爲你索要更詳細的代碼示例:

chunk_size = 3 
L = [1,2,3,4,5,6,7,8,9] 

# iterate over L in steps of 3 
for start in range(0,len(L),chunk_size): # xrange() in 2.x; range() in 3.x 
    end = start + chunk_size 
    print L[start:end] # three-item chunks 

startend值:

[0:3) #[1,2,3] 
[3:6) #[4,5,6] 
[6:9) #[7,8,9] 

FWIW,你可以用map()None初始參數得到同樣的結果:

>>> map(None,*[iter(s)]*3) 
[(1, 2, 3), (4, 5, 6), (7, 8, 9)] 

更多關於zip()map()http://muffinresearch.co.uk/archives/2007/10/16/python-transposing-lists-with-map-and-zip/

+12

這不是迭代器的三個副本,它是同一個迭代器對象的三倍:) – 2010-02-10 04:46:43

5

一個使用拉鍊這個建議的話辦法。它會截斷你的列表,如果它的長度不能被整除。要解決此問題,您可以使用itertools.izip_longest,前提是您可以接受填充值。或者你可以使用這樣的事情:

def n_split(iterable, n): 
    num_extra = len(iterable) % n 
    zipped = zip(*[iter(iterable)] * n) 
    return zipped if not num_extra else zipped + [iterable[-num_extra:], ] 

用法:

for ints in n_split(range(1,12), 3): 
    print ', '.join([str(i) for i in ints]) 

打印:

1, 2, 3 
4, 5, 6 
7, 8, 9 
10, 11 
+2

這已經記錄在'itertools'食譜中:http://docs.python.org/2/library/itertools.html#recipes'石斑魚'。無需重新發明輪子 – jamylak 2013-04-16 07:05:59

21

我認爲,在所有的答案錯過了(可能很明顯,對於熟悉的一件事迭代器),但對其他人不那麼明顯 -

由於我們有相同的迭代器,它得到s消耗,其餘元素由zip使用。所以,如果我們只是使用列表而不是它,例如。

l = range(9) 
zip(*([l]*3)) # note: not an iter here, the lists are not emptied as we iterate 
# output 
[(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5), (6, 6, 6), (7, 7, 7), (8, 8, 8)] 

使用迭代器,彈出的值,僅保留剩餘可用,所以對於拉鍊一旦0被消耗1是可用的,然後2等。一個非常微妙的東西,但很聰明!

+0

+1,你救了我!假設大家都知道這一點,我不能相信其他答案跳過了這個重要的細節。你能否提供包含這些信息的文檔? – 2016-10-06 19:27:33