代码之家  ›  专栏  ›  技术社区  ›  S. L.

为什么zip(*)没有还原我的原始列表

  •  -1
  • S. L.  · 技术社区  · 6 年前

    我想知道发生了什么:

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

    zip(*b) == a
    

    但我得到的是:

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

    2 回复  |  直到 6 年前
        1
  •  2
  •   Martijn Pieters    6 年前

    你漏掉了一个细节 zip() ,作为 outlined in the documentation :

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

    hello world

    例如,如果我们假设 l = 8 (任何大于等于5的内容都会产生您所显示的输出),然后 a 设置为:

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

    第一要素

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

    你只循环了8次,所以只有8个顶级列表 b 从…取信。对于不同的价值观 l 在5个或更多的字符中,您将得到剩余字母的不同分布,但只剩下3个字符,在列表中分布这些剩余字母的方法并不多,而且 8 ,只需添加重复的字母(如 [0::l] [7::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')]
    

    ,因为 zip() next() 要获取第一个(也是唯一的)元素:

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

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

    你得把它们拴起来重新组合起来; itertools.chain.from_iterable() 可以做到:

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

    这只适用于 ,同样,因为 ,用于 l > 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
    
        2
  •  0
  •   AIMEUR Amin    6 年前

    l 真的是!如果你按原样运行它,你肯定会得到一个错误,说l没有定义。

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

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