【问题标题】:Python - Sorting elements in a list of listsPython - 对列表列表中的元素进行排序
【发布时间】:2013-01-04 17:25:01
【问题描述】:

如果已在其他地方回答此问题,我们深表歉意;我试过搜索,但没有找到任何可以回答我问题的东西(或者我有,但不明白)......

我对 Python (v2.6.2) 相当陌生,并且有一个包含浮点值的列表列表,如下所示(除了每个列表的完整内容有 2+ 百万个条目):

cat = [[152.123, 150.456, 151.789, ...], [4.123, 3.456, 1.789, ...], [20.123, 22.456, 21.789, ...]]

现在我想做的是按第三个列表中元素的升序对所有 3 个列表进行排序,这样我得到:

cat_sorted = [[152.123, 151.789, 150.456, ...], [4.123, 1.789, 3.456, ...], [20.123, 21.789, 22.456, ...]]

我已经尝试了一些方法,但它们没有提供我想要的东西(或者我可能没有正确使用它们)。有没有办法做我正在寻找的东西,如果是这样,什么是最简单和最快的(考虑到我有 3 x 200 万个条目)?有没有办法使用另一个列表对一个列表进行排序?

【问题讨论】:

  • 只是想知道这是什么问题,python真的适合这个吗?我还没有看到任何使用 python 处理具有如此大量数据的任务的案例..

标签: python list sorting


【解决方案1】:

这会很痛苦,但是使用默认的 python 你有两个选择:

  • enumerate() 装饰第一个和第二个列表,然后使用索引对它们进行排序以引用第三个列表中的值:

    cat_sorted = [
        [e for i, e in sorted(enumerate(cat[0]), key=lambda p: cat[2][p[0]])],
        [e for i, e in sorted(enumerate(cat[1]), key=lambda p: cat[2][p[0]])],
        sorted(cat[2])
    ]
    

    虽然它可能有助于就地排序cat[2] 而不是使用sorted();其他两个你不能使用sorted()

  • zip() 将三个列表放在一起,然后对这个新列表的第三个元素进行排序,然后再次zip() 回到原来的结构:

    from operator import itemgetter
    cat_sorted = zip(*sorted(zip(*cat), key=itemgetter(2)))
    

两者都不会是性能破坏者,而不是具有数百万个数字的普通 python 列表。

【讨论】:

  • 一旦我弄清楚了 OP 的含义以及描述如何与示例输入和输出相匹配,我的思绪立即跳到了您展示的 zip 方法。给出的问题描述表明,数据一开始并没有真正正确地组织; zip 优雅地解决了这个问题。
  • 太棒了。使用 zip 命令的第二种解决方案效果很好。谢谢您的帮助! :)
【解决方案2】:

如果你愿意使用额外的库,我建议Python Pandas。它有一个类似于 R 的 data.frame 的 DataFrame 对象,并在构造函数中接受列表列表,这将创建一个 3 列数据数组。然后您可以轻松使用内置的pandas.DataFrame.sort 函数按第三列(升序或降序)排序。

有很多简单的 Python 方法可以做到这一点,但考虑到问题的规模,使用 Pandas 中的优化函数是一种更好的方法。如果您需要从已排序的数据中获取任何类型的汇总统计信息,那么 Pandas 是您的不二之选。

【讨论】:

  • +1 用于使用 Pandas——这就是我在写作过程中的内容。其他答案是正确的,但对于如此庞大的数据集,像 Pandas 这样的库才是你真正想要的。
【解决方案3】:

我会采取的一般方法是在整个事情上做一个schwartzian transform

将三个列表压缩成一个元组列表。

使用第三个元素作为键对元组进行排序。

遍历新排序的元组列表并再次填写三个列表。

【讨论】:

    【解决方案4】:

    为了完整起见,一个使用numpy的解决方案:

    import numpy as np
    
    cat = [[152.123, 150.456, 151.789],
            [4.123, 3.456, 1.789],
            [20.123, 22.456, 21.789]]
    
    cat = np.array(cat) 
    cat_sorted = cat[:, cat[2].argsort()]
    
    print cat_sorted
    [[ 152.123  151.789  150.456]
     [   4.123    1.789    3.456]
     [  20.123   21.789   22.456]]
    

    【讨论】:

      【解决方案5】:

      这是基于 Martijn Pieters 和 pcalcao 的出色回答的另一种方法

      def sort_by_last(ll):
          """
              >>> sort_by_last([[10, 20, 30], [3, 2, 1]])
              [[30, 20, 10], [1, 2, 3]]
      
              >>> sort_by_last([[10, 20, 30], [40, 50, 60], [3, 2, 1]])
              [[30, 20, 10], [60, 50, 40], [1, 2, 3]]
      
              >>> sort_by_last([[10, 20, 30], [40, 50, 60], [1, 1, 1]])
              [[10, 20, 30], [40, 50, 60], [1, 1, 1]]
      
              >>> sort_by_last([[10, 20, 30], [40, 50, 60], [1, 3, 1]])
              [[10, 30, 20], [40, 60, 50], [1, 1, 3]]
      
              >>> sort_by_last([[152.123, 150.456, 151.789], [4.123, 3.456, 1.789], [20.123, 22.456, 21.789]])
              [[152.123, 151.789, 150.456], [4.123, 1.789, 3.456], [20.123, 21.789, 22.456]]
          """
          return [sorted(x, key=lambda y: ll[-1][x.index(y)]) for x in ll]
      

      大字符串有一个带有doctest的docstring,用于测试函数将其复制到文件并运行它 python -m doctest -v <file>

      【讨论】:

      • 这里的刺痛是x.index(),这将使大型列表的排序变得很慢
      【解决方案6】:

      这里,keys 是一个排序的索引列表。

      keys = sorted(range(len(cat[2])), key=cat[2].__getitem__)
      cat_sorted = [[cat[i][k] for k in keys] for i in range(3)]
      

      【讨论】:

        猜你喜欢
        • 2016-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多