基于python中嵌套列表中的列表之一进行排序

时间:2012-09-11 11:02:04

标签: python list sorting nested

我的列表为[[4,5,6],[2,3,1]]。现在我想根据list[1]对列表进行排序,即输出应为[[6,4,5],[1,2,3]]。所以基本上我正在排序2,3,1并保持list[0]的顺序。

在搜索时,我得到了一个基于每个列表的第一个元素排序的函数,但不是这个。另外,我不想将列表重新创建为[[4,2],[5,3],[6,1]],然后使用该函数。

4 个答案:

答案 0 :(得分:7)

由于[4, 5, 6][2, 3, 1]有两个不同的目的,我将使用两个参数创建一个函数:要重新排序的列表,以及排序将决定顺序的列表。我只会返回重新排序的列表。

This answer有三种不同解决方案的时间,用于为排序创建排列列表。使用最快的选项可以提供此解决方案:

def pyargsort(seq):
    return sorted(range(len(seq)), key=seq.__getitem__)

def using_pyargsort(a, b):
    "Reorder the list a the same way as list b would be reordered by a normal sort"
    return [a[i] for i in pyargsort(b)]                     

print using_pyargsort([4, 5, 6], [2, 3, 1])    # [6, 4, 5]

pyargsort方法的灵感来自numpy argsort方法,它可以更快地执行相同的操作。 Numpy还具有高级索引操作,可以将数组用作索引,从而可以非常快速地重新排序数组。

因此,如果您对速度的需求很大,那么可以假设这个numpy解决方案会更快:

import numpy as np

def using_numpy(a, b):
    "Reorder the list a the same way as list b would be reordered by a normal sort"
    return np.array(a)[np.argsort(b)].tolist()

print using_numpy([4, 5, 6], [2, 3, 1])     # [6, 4, 5]

但是,对于短列表(长度<1000),此解决方案实际上比第一个慢。这是因为我们首先将ab列表转换为array,然后在返回之前将结果转换回list。如果我们假设你在整个应用程序中使用numpy数组,这样我们就不需要来回转换,我们就得到了这个解决方案:

def all_numpy(a, b):
    "Reorder array a the same way as array b would be reordered by a normal sort"
    return a[np.argsort(b)]

print all_numpy(np.array([4, 5, 6]), np.array([2, 3, 1]))    # array([6, 4, 5])

all_numpy函数的执行速度比using_pyargsort函数快10倍。

以下对数图将这三种解决方案与其他答案中的两种替代解决方案进行了比较。参数是两个等长的随机混洗范围,并且函数都接收相同排序的列表。我只计算函数执行的时间。为了便于说明,我为每个numpy解决方案添加了额外的图形行,其中加载numpy的60 ms开销被添加到时间。

enter image description here

正如我们所看到的,这种全能的解决方案比其他解决方案高出一个数量级。相比之下,从python list转换回来会大大减慢using_numpy解决方案的速度,但对于大型列表,它仍然胜过纯python。

对于大约1'000'000的列表长度,using_pyargsort需要2.0秒,using_nympy +开销仅为1.3秒,而all_numpy +开销为0.3秒。

答案 1 :(得分:5)

您描述的排序不是很容易实现。我能想到的唯一方法是使用zip来创建您不想创建的列表:

lst = [[4,5,6],[2,3,1]]
# key = operator.itemgetter(1) works too, and may be slightly faster ...
transpose_sort = sorted(zip(*lst),key = lambda x: x[1])
lst = zip(*transpose_sort)

这种约束是否有原因?

(另请注意,如果你真的想要,你可以在一行中完成这一切:

lst = zip(*sorted(zip(*lst),key = lambda x: x[1]))

这也会产生一个元组列表。如果您真的想要列表,可以map结果:

lst = map(list, lst)

或者列表理解也可以起作用:

lst = [ list(x) for x in lst ]

答案 2 :(得分:0)

如果第二个列表不包含重复项,您可以这样做:

l = [[4,5,6],[2,3,1]]   #the list
l1 = l[1][:]            #a copy of the to-be-sorted sublist
l[1].sort()             #sort the sublist
l[0] = [l[0][l1.index(x)] for x in l[1]] #order the first sublist accordingly

(由于这会保存子列表l [1],如果您的输入列表很大,则可能不是一个好主意)

答案 3 :(得分:0)

这个怎么样:

a = [[4,5,6],[2,3,1]]
[a[0][i] for i in sorted(range(len(a[1])), key=lambda x: a[1][x])]

它使用numpy的主要方式,而不必使用numpy和没有zip的东西。

对于巨型结构来说,使用numpy和zipping周围似乎都不是最便宜的方式。不幸的是,.sort()方法内置于list类型,并使用对列表中元素的硬连线访问(覆盖__getitem__()或类似方法在此处没有任何影响。)

因此,您可以实现自己的sort(),根据一个值中的两个或多个列表进行排序;这基本上就是numpy所做的。

或者您可以创建一个值列表来对其进行排序,排序,并从中重新创建已排序的原始列表。