Python中基于嵌套列表中的一个列表排序

t0ybt7op  于 2023-04-04  发布在  Python
关注(0)|答案(4)|浏览(202)

我有一个列表[[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]]列表,然后使用该函数。

iklwldmw

iklwldmw1#

由于[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方法的灵感来自numpyargsort方法,后者做同样的事情要快得多。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倍。
下面的逻辑图将这三个解决方案与其他答案中的两个替代解决方案进行比较。参数是两个随机 Shuffle 的等长范围,所有的函数都接收相同的有序列表。我只计算函数执行的时间。为了说明的目的,我我为每个numpy解决方案添加了一个额外的图形行,其中加载numpy的60毫秒开销被添加到时间中。

正如我们所看到的,全numpy的解决方案比其他的解决方案好一个数量级。从python list转换回来,相比之下,using_numpy解决方案的速度要慢得多,但对于大型列表,它仍然优于纯python。
对于大约1'000'000的列表长度,using_pyargsort花费2.0秒,using_nympy +开销仅为1.3秒,而all_numpy +开销为0.3秒。

uqcuzwp8

uqcuzwp82#

你所描述的排序并不容易完成。我能想到的唯一方法是使用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)

这种限制有什么原因吗?
(Also请注意,如果你真的想这样做,你可以在一行中完成所有这些:

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

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

lst = map(list, lst)

或者列表解析也可以工作:

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

5uzkadbs3#

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

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

(As这会保存子列表l[1],如果输入列表很大,这可能是个坏主意)

mfuanj7w

mfuanj7w4#

这个怎么样

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和压缩似乎都不是巨大结构最便宜的方法。不幸的是,.sort()方法内置于list类型中,并使用硬连接访问列表中的元素(重写__getitem__()或类似的方法在这里没有任何效果)。
所以你可以实现你自己的sort(),它根据一个列表中的值对两个或多个列表进行排序;这基本上就是numpy所做的。
或者你可以创建一个值的列表来排序,排序,然后从中重新创建排序后的原始列表。

相关问题