首页 > 解决方案 > 为什么 zip(*) 没有恢复我的原始列表

问题描述

我试图了解正在发生的事情:

a = list('hello world')
b = [a[i::l]for i in range(8)]

然后我会期望:

zip(*b) == a

但是我得到的是以下内容:

 [('h', 'e', 'l', 'l', 'o', ' ', 'w', 'o')]

也许我无法理解 zip(*) 的作用,但我认为它会解压缩列表列表并从中生成一个列表。我哪里错了?

标签: pythonlist

解决方案


zip()文档中所述,您错过了特定于 的详细信息:

当最短的输入迭代用尽时,迭代器停止

hello world其中有 11 个字符,一个素数,因此除了每个字符的 11 个单独序列的列表之外,如果没有至少一个更短的列表,就无法生成列表列表。

例如,如果我们假设l = 8(5 岁及以上的任何东西都会产生您显示的输出),则a设置为:

[['h', 'r'], ['e', 'l'], ['l', 'd'], ['l'], ['o'], [' '], ['w'], ['o']]

那是 8 个列表,第一个包含 2 个元素,其余的只有一个。因此,只有其中的第一个元素用于生成组合:

>>> [l[0] for l in b]
['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o']

您只循环了 8 次,因此只有 8 个顶级列表b可以从中获取字母。对于l5 或​​以上的不同值,您将获得剩余字母的不同分布,但只剩下 3 个字符,没有太多方法可以在列表中分配这些剩余字母,并且在l下面8,您只需添加重复的字母(因为[0::l]并且[7::l]保证在l等于或小于 7 时重叠)。

您必须循环最多 11 次并获取每 11 个字符才能获得将压缩到相同序列的内容:

>>> b = [a[i::11]for i in range(11)]
>>> b
[['h'], ['e'], ['l'], ['l'], ['o'], [' '], ['w'], ['o'], ['r'], ['l'], ['d']]
>>> list(zip(*b))
[('h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd')]

这仍然与 不同a,因为zip()产生序列序列(这里只有一个,因为每个嵌套列表中只有一个值)。您可以next()用来获取第一个(也是唯一一个)元素:

>>> a == list(next(zip(*b)))
True

您可以改为使用itertools.zip_longest()继续迭代,直到用尽最长的输入迭代,并添加默认填充值以增加较短的序列。如果您想再次将序列连接回整个字符串,则可以使用空字符串:

try:
    # Python 3
    from itertools import zip_longest
except ImportError:
    # Python 2 has the same object, but with i prefixed
    from itertools import izip_longest as zip_longest

result = list(zip_longest(*b, fillvalue=''))

然而,这会产生两个元组;毕竟,输入中有两列:

>>> from itertools import zip_longest
>>> b = [a[i::8]for i in range(8)]
>>> list(zip_longest(*b, fillvalue=''))
[('h', 'e', 'l', 'l', 'o', ' ', 'w', 'o'), ('r', 'l', 'd', '', '', '', '', '')]

您必须将它们链接起来才能重新组合它们;itertools.chain.from_iterable()可以这样做:

>>> from itertools import chain
>>> ''.join(chain.from_iterable(zip_longest(*b, fillvalue='')))
'hello world'

这仅适用于, 再次,因为, Forl = 8的较低值的重叠切片,您从末尾开始缺少字符,因为 8 个切片中没有一个包含这些字符ll > 8a[i::l]

>>> for l in range(2, 12):
...     print(f'{l:>2d}:', ''.join(chain.from_iterable(zip_longest(*[a[i::l] for i in range(8)], fillvalue=''))))
...
 2: hello wollo worlo worldworldrldd
 3: hello wolo worldworldld
 4: hello woo worldrld
 5: hello wo worldd
 6: hello woworld
 7: hello woorld
 8: hello world
 9: hello wold
10: hello wod
11: hello wo

推荐阅读