Python - 对列表中的列表元素进行排序

5

抱歉如果这个问题已经在其他地方回答过了; 我尝试了搜索,但没有找到任何可以回答我的问题的内容 (或者我可能已经找到了,但是没有理解它) ...

我相对较新于 Python (v2.6.2),并有一个包含浮点值的列表,看起来像以下这样(除了完整的列表每个条目都有2+百万项):

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

现在我想要做的是按照第三个列表元素的升序对这三个列表进行排序,以便获得以下结果:
cat_sorted = [[152.123, 151.789, 150.456, ...], [4.123, 1.789, 3.456, ...], [20.123, 21.789, 22.456, ...]]

我尝试了几种方法,但它们没有给我我想要的结果(或者可能我使用它们不正确)。有没有一种方法可以做到我想要的,如果可以的话,最容易和最快的方法是什么(考虑到我有三个200万条目)?有没有一种方法可以使用另一个列表来排序一个列表?


只是想知道这是什么问题,Python真的适合处理这个吗?我还没有看到使用Python处理如此大量数据的情况。 - Ixanezis
6个回答

8

这可能有点麻烦,但使用默认的Python,您有两个选项:

  • decorate the 1st and 2nd lists with enumerate(), then sort these using the index to refer to values from the 3rd list:

    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])
    ]
    

    although it may help to sort cat[2] in-place instead of using sorted(); you cannot get around using sorted() for the other two.

  • zip() the three lists together, then sort on the third element of this new list of lists, then zip() again to get back to the original structure:

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

这不会成为性能瓶颈,特别是当涉及到使用包含数百万个数字的普通Python列表时。


一旦我弄清楚了 OP 的意思以及描述如何与示例输入和输出相匹配,我的脑海立刻想到了你展示的“zip”方法。所给出的问题描述表明数据一开始并没有被正确组织;而“zip”方法则优雅地解决了这个问题。 - Karl Knechtel
太棒了。使用zip命令的第二个解决方案完美运行。感谢您的帮助! :) - Shanagar

4
如果你愿意使用额外的库,我建议使用 Python Pandas。它有一个类似于R中的data.frame 的DataFrame对象,并且在构造函数中接受一个列表的列表,这将创建一个3列数据数组。然后,您可以轻松地使用内置的 pandas.DataFrame.sort 函数按第三列排序(升序或降序)。
有很多普通的Python方法来做到这一点,但考虑到你的问题规模,使用Pandas中优化的函数是更好的方法。如果你需要从你的排序数据中获得任何类型的聚合统计信息,那么Pandas对此来说是再简单不过的了。

+1 for使用Pandas - 这正是我正在编写的内容。其他答案都是正确的,但对于如此大的数据集,像Pandas这样的库才是你真正想要的。 - Iguananaut

2
我会采用的一般方法是对整个内容进行Schwartzian变换
将这三个列表压缩成一个元组列表。
使用第三个元素作为关键字对元组进行排序。
遍历新排序的元组列表,并再次填充这三个列表。

1
为了完整起见,这里提供使用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]]

0

这里是另一种做法,基于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的文档字符串,要测试该函数,请将其复制到文件中并使用以下命令运行:python -m doctest -v <file>


这里的问题在于 x.index(),对于大型列表来说会使排序变得相当缓慢。 - John La Rooy

0

这里,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)]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接