【问题标题】:Converting a list of tuples into a simple flat list [duplicate]将元组列表转换为简单的平面列表[重复]
【发布时间】:2012-09-03 12:59:22
【问题描述】:

可能重复:
How do I convert a tuple of tuples to a one-dimensional list using list comprehension?

假设我有以下元组列表:

[(1,2), (1,3), (1,4), (1,5), (1,6)]

我正在尝试将其转换为如下所示的简单列表:

[1,2,1,3,1,4,1,5,1,6]

如何将其转换为像上面这样的简单列表,而不必遍历每个元素并将项目逐个添加到另一个列表中?

是否有任何快速有效的方法可以做到这一点,而无需实际遍历原始元组列表,或者是否有一些内置函数/方法可以做到这一点?

【问题讨论】:

  • 我认为没有隐式遍历元组的方法。
  • @jonathanmarvens:我认为“不必遍历每个元素”,OP 意味着使用显式的 for 循环。
  • 当然,“[e for l in lst for e in l]”(来自大卫罗宾逊的回答)是最快的方法,但我认为如果没有 [隐式] 实际迭代,这是不可能的通过元组的原始列表”。即使您使用一些“内置函数/方法”,这也是它必须在幕后做的事情。
  • @DavidRobinson 好的。我只是想确保他明白这一点。
  • 我知道如果不隐式迭代元组,可能没有办法做到这一点。 @DavidRobinson 是对的。我试图避免明确使用“for”循环。

标签: python


【解决方案1】:
lst = [(1,2), (1,3), (1,4), (1,5), (1,6)]

import itertools
list(itertools.chain(*lst))
# [1, 2, 1, 3, 1, 4, 1, 5, 1, 6]

或者:

[e for l in lst for e in l]
# [1, 2, 1, 3, 1, 4, 1, 5, 1, 6]

【讨论】:

  • 我一定会的。我也将尝试列表理解。我正在运行几个基准测试。因为我不会导入任何模块,所以它可能会让我的工作完成得更快。 @ovgolovin 还在下面提出了一些建议,我会尝试看看它是否更快。
  • @davidadamojr 根据this excellent answer,列表推导版本更快。
  • @DavidRobinson 自该答案发布以来,他们已经进行了很多优化。从那以后可能发生了很多变化。在 Python 3 中尤其是与速度相关的主要变化。可以肯定的是,速度测试应该在当前使用的 Python 版本中进行。
  • @DavidRobinson 这是 BDFL 写的文章:python-history.blogspot.com/2010/06/…
【解决方案2】:

从根本上说,哪个更快?使用“itertools”模块,还是使用列表理解?我基本上是想提高我的计算速度。 - @davidadamojr

我一直在做一些测试,我发现下面的代码实际上更快。

list_ = [(1, 2), (1, 3), (1, 4), (1, 5), (1, 6)]
list(sum(list_, ()))

如果我错了,有人纠正我。

下面是一些测试。

>>> list_ = [(1, 2), (1, 3), (1, 4), (1, 5), (1, 6)]
>>> 
>>> operation_1 = lambda: [tuple_item for tuple_ in list_ for tuple_item in tuple_]
>>> def operation_2 ():
        final_list = []
        for tuple_ in list_:
            for tuple_item in tuple_:
                final_list.append(tuple_item)
        return final_list

>>> operation_3 = lambda: reduce(list.__add__, map(list, list_))
>>> def operation_4 ():
        import itertools
        return list(itertools.chain(*list_))

>>> operation_5 = lambda: list(sum(list_, ()))
>>> 
>>> operation_1()
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]
>>> operation_2()
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]
>>> operation_3()
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]
>>> operation_4()
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]
>>> operation_5()
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]
>>> 
>>> import timeit
>>> 
>>> print('operation_1 completed in %s seconds.' % (timeit.timeit(operation_1)))
operation_1 completed in 1.57890490223 seconds.
>>> print('operation_2 completed in %s seconds.' % (timeit.timeit(operation_2)))
operation_2 completed in 2.90350501659 seconds.
>>> print('operation_3 completed in %s seconds.' % (timeit.timeit(operation_3)))
operation_3 completed in 5.08437990236 seconds.
>>> print('operation_4 completed in %s seconds.' % (timeit.timeit(operation_4)))
operation_4 completed in 3.85125378138 seconds.
>>> print('operation_5 completed in %s seconds.' % (timeit.timeit(operation_5)))
operation_5 completed in 1.2623826489 seconds.

【讨论】:

  • 当然,这些操作都不会递归地变平。它们仅在一个级别上变平。为避免重写其他人所做的事情,请单击 here 访问有关递归扁平化的文章。这是一篇旧文章(从 2006 年开始),但我认为这不应该成为问题。
  • 嘿@jonathanmarvens,我也进行了测试,确实 operation_5 似乎是最快的。太好了!
  • @davidadamojr 我很高兴它对你有用!如果您不介意,如果您支持我的回答,我将不胜感激。谢谢。
【解决方案3】:

使用chain.from_iterable,因为它通过懒惰地推进列表来避免不必要的一次性解包(这会导致多余的内存消耗):

>>> import itertools
>>> L = [(1,2), (1,3), (1,4), (1,5), (1,6)]
>>> list(itertools.chain.from_iterable(L))
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]

【讨论】:

  • 这是最简单、最 Pythonic 的答案。它应该更高。
【解决方案4】:

就性能和特殊模块(如 itertools)的独立性而言,这是最好的方法:

>>> l = [(1,2), (1,3), (1,4), (1,5), (1,6)] 
>>> reduce(list.__add__,map(list,l))
[1, 2, 1, 3, 1, 4, 1, 5, 1, 6]

【讨论】:

  • 这是否比使用上面一些答案中显示的列表理解更快更有效?
猜你喜欢
  • 2012-05-24
  • 2017-03-24
  • 2020-01-26
  • 1970-01-01
  • 2017-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-08
相关资源
最近更新 更多