简体   繁体   English

为什么zip(*)无法恢复我的原始列表

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM