【问题标题】:How to group multiple lists into single list in a Pythonic way?如何以 Pythonic 方式将多个列表分组为单个列表?
【发布时间】:2019-09-03 22:33:58
【问题描述】:

我有一个从列表列表返回列表的函数,其中返回列表按索引号对每个列表的成员进行分组。代码及示例:

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、generators 等使这个更 Pythonic?我看过像this 这样的例子,但在我的代码中,单个列表的元素没有交互。谢谢

【问题讨论】:

  • 如果列表的长度不同怎么办?那你有什么要求呢?
  • 断言防止这种情况,它们不应该根据程序的逻辑

标签: python


【解决方案1】:

使用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]

【讨论】:

    【解决方案2】:

    在正常情况下,我也会使用 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 不,它们实际上是相同的。不过,我个人觉得chain.from_iterable(zip(*[a, b, c])) 比理解方法更易读。
    • 谢谢,我接受这个答案,因为在这些情况下,列表推导可以是 efficient,没有额外的依赖项
    • @shanlodh,您可能还感兴趣:stackoverflow.com/questions/49631326/…
    • @Austin:谢谢,有趣的链接,特别是链接 OP 下的 zwer 的 cmets,这反映了我在这种情况下的经验。我的 OP func 似乎比实际代码中更多 Pythonic 解决方案运行得更快
    【解决方案3】:

    使用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]
    

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

    【讨论】:

      【解决方案4】:

      您可以使用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]
      

      祝你好运。

      【讨论】:

      • 请注意,这些是lists,而不是arrays
      猜你喜欢
      • 1970-01-01
      • 2011-08-15
      • 2010-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-10
      • 1970-01-01
      相关资源
      最近更新 更多