如何以Pythonic的方式将多个列表合并为一个列表?

3

我有一个函数,它从列表的列表中返回一个列表,其中返回的列表根据索引号将每个列表的成员分组。以下是代码和示例:

def listjoinervar(*lists: list) -> list:
    """returns list of grouped values from each list 
        keyword arguments:
        lists: list of input lists
    """ 
    assert(len(lists) > 0) and (all(len(i) == len(lists[0]) for i in lists))
    joinedlist = [None] * len(lists) * len(lists[0])
    for i in range(0, len(joinedlist), len(lists)):
        for j in range(0, len(lists[0])):
            joinedlist[i//len(lists[0]) + j*len(lists[0])] = lists[i//len(lists[0])][j]
    return joinedlist

a = ['a', 'b', 'c']
b = [1, 2, 3]
c = [True, False, False]
listjoinervar(a, b, c)
# ['a', 1, True, 'b', 2, False, 'c', 3, False]

有没有使用itertools、生成器等更Pythonic的方法?我看过像这样的示例,但在我的代码中,各个列表元素之间没有交互。谢谢

如果列表长度不同怎么办?那你的要求是什么? - Underoos
断言可以防止这种情况发生,根据程序的逻辑,它们不应该出现。 - shanlodh
4个回答

7

使用itertools.chain.from_iterable + zip

from itertools import chain

def listjoinervar(*a):
    return list(chain.from_iterable(zip(*a)))

使用方法:

>>> a = ['a', 'b', 'c']
>>> b = [1, 2, 3]
>>> c = [True, False, False]
>>> listjoinervar(a, b, c)
['a', 1, True, 'b', 2, False, 'c', 3, False]

3
在正常情况下,我也会使用 itertools.chain,就像 Austin 的回答一样。
然而,为了完整起见,还有另一种不需要导入任何东西的解决方案:
def join_lists(*a):
    return [element for sub in zip(*a) for element in sub]

a = ['a', 'b', 'c']
b = [1, 2, 3]
c = [True, False, False]

join_lists(a, b, c)

输出:

['a', 1, True, 'b', 2, False, 'c', 3, False]

谢谢,你能解释一下在“正常情况”下为什么要使用itertools.chain吗?似乎这可以不用它来完成。itertools.chain还有其他好处吗? - shanlodh
@shanlodh 不,它们实际上是相同的。然而,我个人认为chain.from_iterable(zip(*[a, b, c]))比推导式方法稍微更易读一些。 - gmds
谢谢,我接受这个答案,因为在这些情况下,列表推导可以高效地完成,而无需额外的依赖。 - shanlodh
@shanlodh,您可能也会对以下内容感兴趣:https://dev59.com/BFUL5IYBdhLWcg3w47k5 - Austin
@Austin:谢谢,有趣的链接,特别是在链接的OP下面的zwer的评论,这与我的经验相似。在实际代码中,我的OP函数似乎比更Pythonic的解决方案运行得更快。 - shanlodh

1
使用zip和列表推导式:

from typing import List, Any

def listjoinervar(*args: List[Any]) -> List[Any]:
    return [item for sublist in list(zip(*args)) for item in sublist]

使用方法:

>>> a = ["a", "b", "c"]
>>> b = [1, 2, 3]
>>> c = [True, False, False]
>>> listjoinervar(a,b,c)
['a', 1, True, 'b', 2, False, 'c', 3, False]

类型注释的使用是可选的。


0

你可以不导入任何东西,使用 enumeratemax 方法来实现:

def custom_group(*args):
  biggest, result = max(args, key = lambda x: len(x)), []
  for (i, value) in enumerate(biggest):
    for arr in args:
      if len(arr) > i:
        result.append(arr[i])
  return result

你正在循环遍历最大的列表,并将每个列表中该索引处的值(如果存在)添加到结果列表中,然后继续移动到下一个索引,直到循环停止。

使用您指定的数组:

a = ["a", "b", "c"]
b = [1, 2, 3]
c = [True, False, False]

你可以这样调用函数:

print(custom_group(a,b,c))

这应该导致以下列表被输出:

["a", 1, True, "b", 2, False, "c", 3, False]

祝好运。


1
请注意这些是列表而不是数组 - gmds

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