【问题标题】:Transform "list of tuples" into a flat list or a matrix将“元组列表”转换为平面列表或矩阵
【发布时间】:2012-05-24 20:38:07
【问题描述】:

使用 Sqlite,select .. from 命令返回结果output,它会打印:

>>print output
[(12.2817, 12.2817), (0, 0), (8.52, 8.52)]

这似乎是一个元组列表。我想将output 转换为一个简单的列表:

[12.2817, 12.2817, 0, 0, 8.52, 8.52]

或 2x3 矩阵:

12.2817 12.2817
0          0 
8.52     8.52

通过output[i][j]阅读

flatten 命令对第一个选项不起作用,我不知道第二个...

我们将不胜感激快速的解决方案,因为实际数据要大得多。

【问题讨论】:

标签: python list tuples


【解决方案1】:
>>> flat_list = []
>>> nested_list = [(1, 2, 4), (0, 9)]
>>> for a_tuple in nested_list:
...     flat_list.extend(list(a_tuple))
... 
>>> flat_list
[1, 2, 4, 0, 9]
>>> 

您可以轻松地从元组列表移动到单个列表,如上所示。

【讨论】:

    【解决方案2】:

    如果是任意嵌套列表(以防万一):

    def flatten(lst):
        result = []
        for element in lst: 
            if hasattr(element, '__iter__'):
                result.extend(flatten(element))
            else:
                result.append(element)
        return result
    
    >>> flatten(output)
    [12.2817, 12.2817, 0, 0, 8.52, 8.52]
    

    【讨论】:

      【解决方案3】:

      或者您可以像这样展平列表:

      reduce(lambda x,y:x+y, map(list, output))
      

      【讨论】:

      • reduce(lambda x,y:x+y, output) 似乎可以直接转换为长元组(可以转换为列表)。为什么在reduce() 调用中使用map(list, output)?或许更符合tuples are immutable, lists are mutable的事实。
      【解决方案4】:

      使用itertools链:

      >>> import itertools
      >>> list(itertools.chain.from_iterable([(12.2817, 12.2817), (0, 0), (8.52, 8.52)]))
      [12.2817, 12.2817, 0, 0, 8.52, 8.52]
      

      【讨论】:

        【解决方案5】:

        迄今为止发布的最快(和最短)的解决方案:

        list(sum(output, ()))
        

        itertools 解决方案快约50%,比map 解决方案快约70%。

        【讨论】:

        • @Joel 很好,但我想知道它是如何工作的? list(output[0]+output[1]+output[2]) 给出了想要的结果,但 list(sum(output)) 没有。为什么? () 有什么“魔力”?
        • 好的,我应该阅读手册g。似乎 sum(sequence[, start]): sum 添加 start 默认为 0 而不是从 sequence[0] 开始(如果存在),然后添加其余元素。很抱歉打扰您。
        • 这是一个众所周知的反模式:不要使用sum 连接序列,它会导致二次时间算法。确实,如果您尝试使用字符串执行此操作,sum 函数会报错!
        • @juanpa.arrivillaga:同意。很少有这样的用例更可取。
        • 是的,速度很快,但完全迟钝。您必须对它实际在做什么发表评论:(
        【解决方案6】:

        在 Python 2.7 和所有版本的 Python3 中,您可以使用 itertools.chain 来展平可迭代列表。使用* 语法或类方法。

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

        【讨论】:

          【解决方案7】:

          更新:使用扩展但没有理解且不使用列表作为迭代器进行展平(最快)

          在检查下一个答案后,通过dual for 的列表理解提供了一个更快的解决方案,我做了一些调整,现在它表现更好,首先执行 list(...) 拖了很大一部分时间,然后更改一个简单循环的列表推导也减少了一点。

          新的解决方案是:

          l = []
          for row in output: l.extend(row)
          

          [] 替换list 的旧版本(有点慢但不多):

          [l.extend(row) for row in output]
          

          较旧(较慢):

          使用列表理解进行展平

          l = []
          list(l.extend(row) for row in output)
          

          新扩展的一些时间和通过删除 [...] 的 list(...) 获得的改进:

          import timeit
          t = timeit.timeit
          o = "output=list(zip(range(1000000000), range(10000000))); l=[]"
          steps_ext = "for row in output: l.extend(row)"
          steps_ext_old = "list(l.extend(row) for row in output)"
          steps_ext_remove_list = "[l.extend(row) for row in output]"
          steps_com = "[item for sublist in output for item in sublist]"
          
          print(f"{steps_ext}\n>>>{t(steps_ext, setup=o, number=10)}")
          print(f"{steps_ext_remove_list}\n>>>{t(steps_ext_remove_list, setup=o, number=10)}")
          print(f"{steps_com}\n>>>{t(steps_com, setup=o, number=10)}")
          print(f"{steps_ext_old}\n>>>{t(steps_ext_old, setup=o, number=10)}")
          

          结果的时间:

          for row in output: l.extend(row)                  
          >>> 7.022608777000187
          
          [l.extend(row) for row in output]
          >>> 9.155910597999991
          
          [item for sublist in output for item in sublist]
          >>> 9.920002304000036
          
          list(l.extend(row) for row in output)
          >>> 10.703829122000116
          

          【讨论】:

            【解决方案8】:

            列表理解方法适用于 Iterable 类型,并且比此处显示的其他方法更快。

            flattened = [item for sublist in l for item in sublist]
            

            l 是要展平的列表(在 OP 的情况下称为 output


            timeit 测试:

            l = list(zip(range(99), range(99)))  # list of tuples to flatten
            

            列表理解

            [item for sublist in l for item in sublist]
            

            timeit 结果 = 7.67 µs ± 129 ns 每个循环

            列出extend()方法

            flattened = []
            list(flattened.extend(item) for item in l)
            

            timeit 结果 = 11 µs ± 433 ns 每个循环

            sum()

            list(sum(l, ()))
            

            timeit 结果 = 24.2 µs ± 269 ns 每个循环

            【讨论】:

            • 我必须在大型数据集上使用它,列表理解方法是迄今为止最快的!
            • 我对 .extend 解决方案做了一点改动,现在表现更好了。看看你的时间它比较
            【解决方案9】:

            这就是 numpy 的用途,无论是从数据结构还是速度角度。

            import numpy as np
            
            output = [(12.2817, 12.2817), (0, 0), (8.52, 8.52)]
            output_ary = np.array(output)   # this is your matrix 
            output_vec = output_ary.ravel() # this is your 1d-array
            

            【讨论】:

              【解决方案10】:
              def flatten_tuple_list(tuples):
                  return list(sum(tuples, ()))
              
              
              tuples = [(5, 6), (6, 7, 8, 9), (3,)]
              print(flatten_tuple_list(tuples))
              

              【讨论】:

              • 感谢您提供答案。您能否编辑您的答案以包括对您的代码的解释?这将帮助未来的读者更好地理解正在发生的事情,尤其是那些不熟悉该语言并努力理解这些概念的社区成员。这在这里特别有用,因为您的答案正在与其他九个答案竞争注意力。你的有什么区别?什么时候这比上述公认的答案更受欢迎?
              • 好的,我会这样做的
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2022-10-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-09-18
              • 2017-12-22
              • 2019-04-23
              相关资源
              最近更新 更多