Pythonic方式以交替的方式组合两个列表?

dav*_*ers 75 python

我有两个列表,第一个列表保证只包含一个列表而不是第二个列表.我想知道创建一个新列表的最Pythonic方法,其中偶数索引值来自第一个列表,其奇数索引值来自第二个列表.

# example inputs
list1 = ['f', 'o', 'o']
list2 = ['hello', 'world']

# desired output
['f', 'hello', 'o', 'world', 'o']
Run Code Online (Sandbox Code Playgroud)

这有效,但并不漂亮:

list3 = []
while True:
    try:
        list3.append(list1.pop(0))
        list3.append(list2.pop(0))
    except IndexError:
        break
Run Code Online (Sandbox Code Playgroud)

如何实现这一目标呢?什么是最Pythonic方法?

Dun*_*can 93

这是切片的一种方法:

>>> list1 = ['f', 'o', 'o']
>>> list2 = ['hello', 'world']
>>> result = [None]*(len(list1)+len(list2))
>>> result[::2] = list1
>>> result[1::2] = list2
>>> result
['f', 'hello', 'o', 'world', 'o']
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,邓肯.我没有意识到切片时可以指定一个步骤.我喜欢这种方法的是它自然的读取方式.1.列出正确的长度.2.使用list1的内容填充偶数索引.3.使用list2的内容填充奇数索引.在这种情况下,列表具有不同长度的事实不是问题! (2认同)
  • 我认为它仅在len(list1)-len(list2)为0或1时有效。 (2认同)

Dav*_*d Z 47

itertools文档中有一个配方:

from itertools import cycle, islice

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    pending = len(iterables)
    nexts = cycle(iter(it).next for it in iterables)
    while pending:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            pending -= 1
            nexts = cycle(islice(nexts, pending))
Run Code Online (Sandbox Code Playgroud)

  • @Manoj飞.你需要反重力模块 (23认同)
  • itertools有什么不能做的吗?+1. (20认同)
  • 我发现这种方式比需要的更复杂。下面有一个更好的选择,使用“zip_longest”。 (2认同)

Mar*_*ers 27

这应该做你想要的:

>>> iters = [iter(list1), iter(list2)]
>>> print list(it.next() for it in itertools.cycle(iters))
['f', 'hello', 'o', 'world', 'o']
Run Code Online (Sandbox Code Playgroud)

  • 用于解决所述问题的+1,并且也是为了这样做:-)我认为这样的事情是可能的.老实说,我认为`roundrobin`功能对于这种情况来说有点过分. (4认同)

use*_*640 25

import itertools
print [x for x in itertools.chain.from_iterable(itertools.izip_longest(list1,list2)) if x]
Run Code Online (Sandbox Code Playgroud)

我认为这是做到这一点的最蟒蛇的方式.

  • 方法名称是zip_longest而不是izip_longest (5认同)
  • 比接受的答案要好得多! (4认同)
  • 为什么这不是公认的答案?这是最短和最pythonic,并使用不同的列表长度! (3认同)
  • 注意:如果列表包含值为“False”的元素,甚至是仅由“if”表达式评估为“False”的元素,例如“0”或空列表,这将导致问题。这可以通过以下方式(部分)避免:“[x for x in itertools.chain.from_iterable(itertools.zip_longest(list1, list2)) if x is not None]”。当然,如果列表包含需要保留的“None”元素,这仍然不起作用。在这种情况下,您需要更改“zip_longest”的“fillvalue”参数,正如 Dubslow 已经建议的那样。 (3认同)
  • 这样做的问题是 zip_longest 的默认填充值可能会覆盖*应该在列表中的“None”。我将编辑一个调整版本来解决这个问题 (2认同)

Zar*_*art 14

没有itertools并假设l1比l2长1项:

>>> sum(zip(l1, l2+[0]), ())[:-1]
('f', 'hello', 'o', 'world', 'o')
Run Code Online (Sandbox Code Playgroud)

使用itertools并假设列表不包含None:

>>> filter(None, sum(itertools.izip_longest(l1, l2), ()))
('f', 'hello', 'o', 'world', 'o')
Run Code Online (Sandbox Code Playgroud)


Arc*_*ast 12

如果两个列表的长度相等,您可以执行以下操作:

[x for y in zip(list1, list2) for x in y]
Run Code Online (Sandbox Code Playgroud)

由于第一个列表还有一个元素,您可以事后添加它:

[x for y in zip(list1, list2) for x in y] + [list1[-1]]
Run Code Online (Sandbox Code Playgroud)

  • ^这应该是答案,Python 在过去 10 年里变得更加 Pythonic (4认同)

mho*_*ost 10

我知道问题是关于两个列表,其中一个项目比另一个项目更多,但我想我会把它放在可能找到这个问题的其他人的名单上.

这是Duncan的解决方案,适用于两个不同大小的列表.

list1 = ['f', 'o', 'o', 'b', 'a', 'r']
list2 = ['hello', 'world']
num = min(len(list1), len(list2))
result = [None]*(num*2)
result[::2] = list1[:num]
result[1::2] = list2[:num]
result.extend(list1[num:])
result.extend(list2[num:])
result
Run Code Online (Sandbox Code Playgroud)

这输出:

['f', 'hello', 'o', 'world', 'o', 'b', 'a', 'r'] 
Run Code Online (Sandbox Code Playgroud)


Jay*_*Jay 6

这是一个这样做的班轮:

list3 = [ item for pair in zip(list1, list2 + [0]) for item in pair][:-1]

  • 这工作正常,但让我觉得不优雅,因为它做了很多事情来实现如此简单的事情。我并不是说这种方法效率低下,只是说它不是特别容易阅读。 (3认同)

归档时间:

查看次数:

54828 次

最近记录:

6 年,1 月 前