我有一个列表作为 [[4,5,6],[2,3,1]]
. 现在我想根据list[1]
ie 输出对列表进行排序应该是 [[6,4,5],[1,2,3]]
. 所以基本上我正在排序2,3,1
和维护list[0]
.
在搜索时,我得到了一个函数,它根据每个列表的第一个元素进行排序,但不是为此。我也不想重新创建列表[[4,2],[5,3],[6,1]]
,然后使用该功能。
由于[4, 5, 6]
和[2, 3, 1]
服务于两个不同的目的,我将创建一个带有两个参数的函数:要重新排序的列表,以及排序将决定顺序的列表。我只会返回重新排序的列表。
该答案具有三种不同解决方案的时间安排,用于为排序创建排列列表。使用最快的选项给出了这个解决方案:
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),这个解决方案实际上比第一个慢。这是因为我们首先将a
andb
列表转换为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 开销被添加到时间中。
正如我们所看到的,全 numpy 解决方案比其他解决方案高出一个数量级。相比之下,从 python 转换list
回来会using_numpy
大大降低解决方案的速度,但对于大型列表,它仍然胜过纯 python。
对于大约 1'000'000 的列表长度,using_pyargsort
需要 2.0 秒,using_nympy
+ 开销仅为 1.3 秒,而all_numpy
+ 开销为 0.3 秒。
你描述的排序不是很容易完成。我能想到的唯一方法是使用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 ]
如果第二个列表不包含重复项,您可以这样做:
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] 如果您的输入列表很大,这可能是个坏主意)
这个怎么样:
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 所做的。
或者,您可以创建一个值列表以对其进行排序、排序,并从中重新创建已排序的原始列表。