如何将一个可迭代对象拆分为两个列表,其中一个列表包含交替的元素?

18

我想把一个可迭代对象拆分成两个列表,每个列表包含交替的元素。这里有一个可行的解决方案。但是是否有更简单的方法来实现同样的功能?

def zigzag(seq):
    """Return two sequences with alternating elements from `seq`"""
    x, y = [], []
    p, q = x, y
    for e in seq:
        p.append(e)
        p, q = q, p
    return x, y

示例输出:

>>> zigzag('123456')
(['1', '3', '5'], ['2', '4', '6'])

参见:提取列表中奇数位置的元素 - Karl Knechtel
另请参阅:提取列表中奇数位置的元素 - undefined
4个回答

50

如果 seq 是一个序列,那么:

def zigzag(seq):
  return seq[::2], seq[1::2]
如果seq是一个完全通用的可迭代对象,例如可能是一个生成器:
def zigzag(seq):
  results = [], []
  for i, e in enumerate(seq):
    results[i%2].append(e)
  return results

2
@Sridhar,不要认为这是懒惰,而应该认为这是高效利用时间。我花了半个小时编写一个算法来使用for循环(对于x列,而不仅仅是两列)来完成这个任务。虽然我最终实现了它,但它似乎并不符合Python的风格——我怀疑是否有更简单的方法。果然,我没有记住列表具有step变量(如此答案中所示),这使得它变得微不足道。 - John C

11

这个函数接受一个迭代器并返回两个迭代器:

import itertools
def zigzag(seq):
    t1,t2 = itertools.tee(seq)
    even = itertools.islice(t1,0,None,2)
    odd = itertools.islice(t2,1,None,2)
    return even,odd

如果你更喜欢列表,那么你可以使用 return list(even),list(odd)

9
def zigzag(seq):
    return seq[::2], seq[1::2]

只适用于列表,而另一个解决方案适用于任何可迭代对象。 - Nick Stinemates
3
明白,但标题确实指明了一个列表。 - cobbal

0

我只是想澄清一些事情。假设你有一个列表

list1 = list(range(200))

你可以选择以下任一方式:

## OPTION A ##
a = list1[1::2]
b = list1[0::2]

或者

## OPTION B ##
a = list1[0:][::2] # even
b = list1[1:][::2] # odd

并且在变量ab中有替代元素。

但是选项A的速度是另一个选项的两倍。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接