【问题标题】:How to merge multiple lists by their indices如何按索引合并多个列表
【发布时间】:2021-06-16 12:25:47
【问题描述】:

我想将一个嵌套列表(其中的列表长度不同)合并为一个。我想先按索引添加。然后按大小排序。

例子:

lsts = [
     [7, 23, 5, 2],
     [3, 8, 1],
     [99, 23, 9, 23, 74]
]

merged = [3, 7, 99, 8, 23, 23, 1, 5, 9, 2, 23, 74]

我想在不导入的情况下解决这个问题。

【问题讨论】:

  • 您是否尝试过在索引上编写循环并使用sorted 函数?

标签: python list indexing merge


【解决方案1】:

假设您的列表不能包含Nones,您可以使用itertools.zip_longest 来做到这一点:

from itertools import zip_longest

result = []
for row in zip_longest(*lsts):
    row = (x for x in row if x is not None)
    for x in sorted(row):
        result.append(x)

print(result)

【讨论】:

  • 非常感谢 - 但我想在不导入的情况下解决这个问题。我现在在我的帖子中也注意到了。
  • 为什么不导入一套很可能比手写代码性能更高的标准工具呢?这可能是编码练习还是学校作业?否则我看不出有充分理由使用标准库导入。
  • 确实,这是一项主要旨在理解逻辑的任务。不过好久没上学了:')
  • FWIW,itertools.zip_longest() 的文档列出了不使用任何导入的代码的 Python 等效项。 itertools.chain() 同上。您可以使用它来构建解决方案,而无需实际导入任何内容。 :)
【解决方案2】:

这是一个单行:

import functools
import itertools

functools.reduce(lambda x,y: x+y, [sorted(x for x in p if x is not None) for p in itertools.zip_longest(*lsts)])

输出:

[3, 7, 99, 8, 23, 23, 1, 5, 9, 2, 23, 74]

【讨论】:

  • 非常感谢 - 但我想在不导入的情况下解决这个问题。我现在在我的帖子中也注意到了。
  • @red_joice 如果你想在不导入的情况下解决它,那么这听起来像是你应该尝试自己解决的家庭作业。你试过什么?你被困在哪里了?
【解决方案3】:

我将在上一步的结果的基础上逐步解释解决方案。

要按索引对每个列表中的项目进行分组,itertools.zip_longest() 是这样做的工具:

>>> import itertools as it

>>> MISSING = object()  # a sentinel

>>> lsts = [
     [7, 23, 5, 2],
     [3, 8, 1],
     [99, 23, 9, 23, 74]
]
>>> it.zip_longest(*lsts, fillvalue=MISSING)
>>> list(_)
[(7, 3, 99), (23, 8, 23), (5, 1, 9), (2, <object object at 0x7f529e9b4260>, 23), (<object object at 0x7f529e9b4260>, <object object at 0x7f529e9b4260>, 74)]

这会在需要时使用 MISSING 填充值将列表元素分组为 n 元组,因为列表的长度可能不相等。

下一步是遍历每个 n 元组并在内部对其进行排序(同时跳过 MISSING 值)。内置函数sorted() 在这里派上用场:

>>> list(
    sorted(x for x in ntuple if x is not MISSING)
    for ntuple in it.zip_longest(*lsts, fillvalue=MISSING)
)
[[3, 7, 99], [8, 23, 23], [1, 5, 9], [2, 23], [74]]

最后一步是展平这个列表序列,我们将使用itertools.chain,from_iterable()

>>> list(it.chain.from_iterable(
        sorted(x for x in ntuple if x is not MISSING)
        for ntuple in it.zip_longest(*lsts, fillvalue=MISSING)
    ))
[3, 7, 99, 8, 23, 23, 1, 5, 9, 2, 23, 74]

chain.from_iterable() 的好处是它不会重复地将较小的列表连接到越来越长的最终列表中,从而提高效率。它也在 C 级别执行此操作,AFAIK。

值得注意的是,None 也可以用来代替 MISSING 哨兵,但我还使用 MISSING 来演示 fillvalue 的工作原理(例如,如果你想使用零或其他东西,如果你希望)。

【讨论】:

    【解决方案4】:

    zip_longest 成功了。剩下的就是清理/格式化

    In [1]: from itertools import zip_longest, chain                                
    
    In [2]: lsts = [ 
    
       ...:      [7, 23, 5, 2], 
       ...:      [3, 8, 1], 
       ...:      [99, 23, 9, 23, 74] 
       ...: ]           
    
    In [3]: [v for v in chain.from_iterable(zip_longest(*lsts)) if v !=None]        
    Out[3]: [7, 3, 99, 23, 8, 23, 5, 1, 9, 2, 23, 74]
    

    【讨论】:

      猜你喜欢
      • 2014-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-08
      • 1970-01-01
      • 2021-03-08
      • 2014-06-24
      相关资源
      最近更新 更多