zip(*[iter(s)]*n) 在 Python 中如何工作?

2024-12-23 08:43:00
admin
原创
88
摘要:问题描述:s = [1,2,3,4,5,6,7,8,9] n = 3 list(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

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

它是如何zip(*[iter(s)]*n)工作的?如果用更详细的代码编写,它会是什么样子?


这是一种将列表分割成大小相等的块的技术——请参阅该问题以了解问题的总体概述。


解决方案 1:

iter()是序列上的迭代器。生成一个包含数量 的[x] * n列表,即长度 的列表,其中每个元素为。将序列解包为函数调用的参数。因此,您将相同的迭代器传递给 3 次,并且每次它都会从迭代器中提取一个项目。n`xnx*argzip()`

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

解决方案 2:

其他出色的答案和评论很好地解释了参数解包zip()的作用。

正如Ignacio和ujukatzel所说,你将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

start遵循和的值end

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

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/

解决方案 3:

我认为所有答案中都遗漏了一件事(对于熟悉迭代器的人来说可能很明显),但对其他人来说却不那么明显 -

由于我们有相同的迭代器,它会被消耗,其余元素由 zip 使用。因此,如果我们只是使用列表而不是 iter,例如。

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 可用,依此类推。非常微妙的事情,但非常聪明!!!

解决方案 4:

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

[iter(s)]*n为 s 创建 n 次相同迭代器的列表。

因此,在执行 时zip(*[iter(s)]*n),它会按顺序从列表中的所有三个迭代器中提取一个项目。由于所有迭代器都是同一个对象,因此它只是将列表分组为n

解决方案 5:

关于以这种方式使用 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

解决方案 6:

解开“聪明才智”的层层谜团,你可能会发现这个等效拼写更容易理解:

x = iter(s)
for a, b, c in zip(*([x] * n)):
    print(a, b, c)

这又相当于更不聪明的做法:

x = iter(accounts_iter)
for a, b, c in zip(x, x, x):
    print(a, b, c)

现在应该开始变得清晰了。只有一个迭代器对象。x在每次迭代中,zip()在幕后,调用next(x)3 次,对传递给它的每个迭代器对象调用一次。但每次都是同一个迭代器对象。因此,它传递前 3 个next(x)结果,并让共享迭代器对象等待接下来传递其第 4 个结果。涂抹、冲洗、重复。

顺便说一句,我怀疑你脑子里解析*([iter(x)]*n)错了。先进行尾随*n,然后将前缀*应用于创建的 n 个元素列表*n。是使用可变数量的参数f(*iterable)进行调用的快捷方式,每个对象传递一个参数。f()`iterable`

解决方案 7:

我需要分解每个部分步骤,才能真正理解它的工作原理。我从 REPL 中得出的笔记:

>>> # refresher on using list multiples to repeat item
>>> lst = list(range(15))
>>> lst
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
>>> # lst id value
>>> id(lst)
139755081359872
>>> [id(x) for x in [lst]*3]
[139755081359872, 139755081359872, 139755081359872]

# replacing lst with an iterator of lst
# It's the same iterator three times
>>> [id(x) for x in [iter(lst)]*3 ]
[139755085005296, 139755085005296, 139755085005296]
# without starred expression zip would only see single n-item list.
>>> print([iter(lst)]*3)
[<list_iterator object at 0x7f1b440837c0>, <list_iterator object at 0x7f1b440837c0>, <list_iterator object at 0x7f1b440837c0>]
# Must use starred expression to expand n arguments
>>> print(*[iter(lst)]*3)
<list_iterator object at 0x7f1b4418b1f0> <list_iterator object at 0x7f1b4418b1f0> <list_iterator object at 0x7f1b4418b1f0>

# by repeating the same iterator, n-times,
# each pass of zip will call the same iterator.__next__() n times
# this is equivalent to manually calling __next__() until complete
>>> iter_lst = iter(lst)
>>> ((iter_lst.__next__(), iter_lst.__next__(), iter_lst.__next__()))
(0, 1, 2)
>>> ((iter_lst.__next__(), iter_lst.__next__(), iter_lst.__next__()))
(3, 4, 5)
>>> ((iter_lst.__next__(), iter_lst.__next__(), iter_lst.__next__()))
(6, 7, 8)
>>> ((iter_lst.__next__(), iter_lst.__next__(), iter_lst.__next__()))
(9, 10, 11)
>>> ((iter_lst.__next__(), iter_lst.__next__(), iter_lst.__next__()))
(12, 13, 14)
>>> ((iter_lst.__next__(), iter_lst.__next__(), iter_lst.__next__()))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

# all together now!
# continuing with same iterator multiple times in list
>>> print(*[iter(lst)]*3)
<list_iterator object at 0x7f1b4418b1f0> <list_iterator object at 0x7f1b4418b1f0> <list_iterator object at 0x7f1b4418b1f0>
>>> zip(*[iter(lst)]*3)
<zip object at 0x7f1b43f14e00>
>>> list(zip(*[iter(lst)]*3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 14)]

# NOTE: must use list multiples. Explicit listing creates 3 unique iterators
>>> [iter(lst)]*3 == [iter(lst), iter(lst), iter(lst)]
False
>>> list(zip(*[[iter(lst), iter(lst), iter(lst)]))
[(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), ....    

解决方案 8:

ipython在 Python 解释器中或者使用以下命令可能更容易看到正在发生的事情n = 2

In [35]: [iter("ABCDEFGH")]*2
Out[35]: [<iterator at 0x6be4128>, <iterator at 0x6be4128>]

因此,我们有一个包含两个迭代器的列表,它们指向同一个迭代器对象。请记住,iter一个对象会返回一个迭代器对象,在这种情况下,由于*2Python 语法糖,它是两次相同的迭代器。迭代器也只运行一次。

此外,zip获取任意数量的可迭代对象(序列是可迭代对象)并从每个输入序列的第 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)描述的方式工作。

解决方案 9:

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

与以下相同:

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

每次zip()获取 中的下一个值时,iter_var它都会移动到 的下一个值x。尝试运行next(iter_var)以查看其工作原理。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1120  
  IPD(Integrated Product Development,集成产品开发)流程是一种广泛应用于高科技和制造业的产品开发方法论。它通过跨职能团队的紧密协作,将产品开发周期缩短,同时提高产品质量和市场成功率。在IPD流程中,CDCP(Concept Decision Checkpoint,概念决策检查点)是一个关...
IPD培训课程   75  
  研发IPD(集成产品开发)流程作为一种系统化的产品开发方法,已经在许多行业中得到广泛应用。它不仅能够提升产品开发的效率和质量,还能够通过优化流程和资源分配,显著提高客户满意度。客户满意度是企业长期成功的关键因素之一,而IPD流程通过其独特的结构和机制,能够确保产品从概念到市场交付的每个环节都围绕客户需求展开。本文将深入...
IPD流程   66  
  IPD(Integrated Product Development,集成产品开发)流程是一种以跨职能团队协作为核心的产品开发方法,旨在通过优化资源分配、提高沟通效率以及减少返工,从而缩短项目周期并提升产品质量。随着企业对产品上市速度的要求越来越高,IPD流程的应用价值愈发凸显。通过整合产品开发过程中的各个环节,IPD...
IPD项目管理咨询   76  
  跨部门沟通是企业运营中不可或缺的一环,尤其在复杂的产品开发过程中,不同部门之间的协作效率直接影响项目的成败。集成产品开发(IPD)作为一种系统化的项目管理方法,旨在通过优化流程和增强团队协作来提升产品开发的效率和质量。然而,跨部门沟通的复杂性往往成为IPD实施中的一大挑战。部门之间的目标差异、信息不对称以及沟通渠道不畅...
IPD是什么意思   70  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用