[英]Why is zip(*) not restoring my original list
I'm trying to understand what is happening: 我试图了解正在发生的事情:
a = list('hello world')
b = [a[i::l]for i in range(8)]
I would then expect that: 然后,我期望:
zip(*b) == a
However what I get is the following: 但是我得到以下内容:
[('h', 'e', 'l', 'l', 'o', ' ', 'w', 'o')]
Maybe it's a failing on my part to understand what zip(*) doe but I thought it unpacks a list of list and makes a single list out of it. 也许我不了解zip(*)的含义,但是我认为它解压缩了一个列表列表,并从中列出了一个列表。 Where am I going wrong? 我要去哪里错了?
You missed a detail specific to zip()
, as outlined in the documentation : 您错过了zip()
的详细信息,如文档所述 :
The iterator stops when the shortest input iterable is exhausted 当最短的输入可迭代数用尽时,迭代器停止
hello world
has 11 characters in it, a prime number, so apart from a list of 11 separate sequences with each one character, there is no way to produce a list of lists without at least one of those being shorter. hello world
有11个字符(质数),因此,除了具有每个字符的11个独立序列的列表之外,如果没有至少一个较短的列表,则无法生成列表列表。
For example, if we presume that l = 8
(anything 5 and over would produce the output you've shown), then a
is set to: 例如,如果我们假定l = 8
(大于等于5的任何值都会产生您显示的输出),则将a
设置为:
[['h', 'r'], ['e', 'l'], ['l', 'd'], ['l'], ['o'], [' '], ['w'], ['o']]
That's 8 lists, with the first containing 2 elements, the remainder have just one. 那是8个列表,第一个包含2个元素,其余的只有一个。 So only the first elements of these are then used to produce combinations: 因此,只有这些元素中的第一个元素才可以用来产生组合:
>>> [l[0] for l in b]
['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o']
You only looped 8 times, so there only 8 top-level lists in b
to take letters from. 您只循环了8次,因此b
只有8个顶级列表可以接收字母。 For different values of l
of 5 or up you'll get a different distribution of the remaining letters but with only 3 more characters remaining there aren't many ways of distributing those remaining letters across the lists, and with l
below 8
, you just add repeated letters (as [0::l]
and [7::l]
are guaranteed to overlap for any l
equal to 7 or lower). 对于l
5或更大的值,您将获得剩余字母的不同分布,但是仅剩余3个字符,就没有很多方法可以在列表中分配剩余字母,而l
小于8
,您只需添加重复的字母(因为对于等于或小于7的任何l
, [0::l]
和[7::l]
都保证重叠)。
You'd have to loop up to 11 times and take every 11th character to get something that'll zip to the same sequence: 您必须循环最多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')]
This still isn't the same as a
, because zip()
produces sequence of sequences (here it's just one because there is only a single value in each nested list). 这仍然是不一样的a
,因为zip()
产生序列的序列(这里只有一个,因为只有在每个嵌套列表中的单个值)。 You could use next()
to get the first (and only) element: 您可以使用next()
获得第一个(也是唯一一个)元素:
>>> a == list(next(zip(*b)))
True
You can instead use itertools.zip_longest()
to continue iteration until the longest input iterable is exhausted, and add a default filler value to augment the shorter sequences. 您可以改为使用itertools.zip_longest()
继续迭代,直到用完最长的可迭代输入为止,并添加默认填充值以增强较短的序列。 An empty string would work if you wanted to join the sequences back to whole strings again: 如果您想再次将序列连接回到整个字符串,则可以使用空字符串:
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=''))
This however produces two tuples; 但是,这将产生两个元组。 there are two columns in the input, after all: 毕竟,输入中有两列:
>>> 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', '', '', '', '', '')]
You'd have to chain them to re-combine them; 您必须将它们链接起来以重新组合它们; itertools.chain.from_iterable()
could do that: itertools.chain.from_iterable()
可以做到这一点:
>>> from itertools import chain
>>> ''.join(chain.from_iterable(zip_longest(*b, fillvalue='')))
'hello world'
This only works for l = 8
, again, because of overlapping slices for lower values of l
, For l > 8
, you start out missing characters from the end as none of the 8 a[i::l]
slices include those characters 这仅适用于l = 8
,再次,因为重叠的切片为较低值的l
,对于l > 8
,你开始缺少从端字符作为没有8的a[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
Your code isn't so clear, and we don't know what the l
really is! 您的代码不清楚,我们也不知道l
到底是什么! if u run it as it is, you will surely get an error saying that the l isn't defined. 如果您按原样运行它,您肯定会得到一条错误消息,说明未定义l。
However, for the zip function it stops at the shortest iterator, to force it keep going you should use zip_longest
. 但是,对于zip函数,它会在最短的迭代器处停止,要使其继续运行,您应该使用zip_longest
。
for more details on how zip function works check this : Python zip 有关zip函数如何工作的更多详细信息,请检查以下内容: Python zip
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.