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)
工作如何?如果用更冗长的代码编写,它将是什么样?
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)
工作如何?如果用更冗长的代码编写,它将是什么样?
Answers:
其他出色的答案和注释很好地解释了参数解压缩和zip()的作用。
就像Ignacio和ujukatzel所说的那样,您传递了zip()
对同一迭代器的三个引用,并zip()
从每个引用到迭代器按顺序生成了三元组的整数:
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
下面的值start
和end
:
[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-transpose-lists-with-map-and-zip/
我认为所有答案中都漏掉了一件事(对熟悉迭代器的人来说可能很明显),而对其他人却不太明显:
由于我们具有相同的迭代器,因此它会被消耗,而其余元素将由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)]
使用迭代器,弹出值并仅保持剩余可用,因此对于zip,一旦消耗了0,则1可用,然后2,依此类推。一件非常微妙的事情,但是非常聪明!!!
iter(s)
返回s的迭代器。
[iter(s)]*n
使s的n次相同迭代器的列表。
因此,在执行时zip(*[iter(s)]*n)
,它将从列表中的所有三个迭代器中依次提取一个项目。由于所有迭代器都是同一个对象,因此只将列表分组为n
。
关于以这种方式使用zip的一个建议。如果长度不能被整除,它将截断您的列表。要解决此问题,如果可以接受填充值,则可以使用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
正是看到什么是在Python解释器发生或可能更容易ipython
使用n = 2
:
In [35]: [iter("ABCDEFGH")]*2
Out[35]: [<iterator at 0x6be4128>, <iterator at 0x6be4128>]
因此,我们有两个指向相同迭代器对象的迭代器的列表。请记住,iter
在一个对象上返回一个迭代器对象,在这种情况下,由于使用*2
python语法糖,它是同一迭代器两次。迭代器也只能运行一次。
此外,zip
采用任意数量的可迭代数(序列为iterables),并从每个输入序列的第i个元素创建元组。由于在我们的例子中,两个迭代器是相同的,因此zip对于输出的每个2元素元组两次将相同的迭代器移动两次。
In [41]: help(zip)
Help on built-in function zip in module __builtin__:
zip(...)
zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]
Return a list of tuples, where each tuple contains the i-th element
from each of the argument sequences. The returned list is truncated
in length to the length of the shortest argument sequence.
该解包(*
)操作者确保迭代器运行至耗尽在这种情况下是,直到没有足够的输入以创建一个2元素的元组。
可以将其扩展为的任何值,n
并zip(*[iter(s)]*n)
按照说明进行操作。
*
只是方便地复制对象。尝试使用标量,然后使用列表。也可以尝试print(*zip(*[iter("ABCDEFG")]*2))
VS print(*zip(*[iter("ABCDEFG"), iter("ABCDEFG")]))
。然后,将它们分解成更小的步骤,以查看两个语句中实际的迭代器对象是什么。