为什么zip(*)不能恢复我原来的lis

2024-04-26 17:37:56 发布

您现在位置:Python中文网/ 问答频道 /正文

我在努力理解发生了什么:

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

我希望:

zip(*b) == a

但我得到的是:

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

也许我没能理解zip(*)的作用,但我认为它可以解压一个列表,并从中生成一个单独的列表。我哪里出错了?你知道吗


Tags: inhello列表forworldrangeziplist
2条回答

你的代码不太清楚,我们也不知道l到底是什么!如果按原样运行,您肯定会得到一个错误,说明l没有定义。你知道吗

但是,对于zip函数,它在最短的迭代器处停止,要强制它继续运行,应该使用zip_longest。你知道吗

有关zip函数如何工作的更多详细信息,请参见:Python zip

您遗漏了一个特定于zip()的细节,如outlined in the documentation

The iterator stops when the shortest input iterable is exhausted

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次,因此b中只有8个顶级列表可以从中获取信件。对于不同的l值5或更高,您将得到不同的剩余字母分布,但只剩下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

您可以改为使用^{}继续迭代,直到用尽longest输入iterable,并添加一个默认填充值来扩充较短的序列。如果您想再次将序列连接回整个字符串,则空字符串将起作用:

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', '', '', '', '', '')]

必须将它们链接起来才能重新组合;^{}可以这样做:

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

这只适用于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

相关问题 更多 >