在保持元素索引的同时对python列表进行排序

时间:2018-01-16 10:58:38

标签: python sorting asort

我需要对python列表进行排序,但排序不应该改变排序前元素的索引。在php中有一个名为asort的函数,但如何在python中执行此操作?有这样的方法吗?如果没有,怎么用更少的线?

例如,请参考以下示例:

$a = [1, 5, 2, 4];
print_r($a);
asort($a);
print_r($a);

输出将是:

Array
(
    [0] => 1
    [1] => 5
    [2] => 2
    [3] => 4
)
Array
(
    [0] => 1
    [2] => 2
    [3] => 4
    [1] => 5
)

此处5在asort之后仍然有索引1,但它已经排序到最后。

我有自己的解决方案,即:将索引创建为整数列表。然后使用[列表长度]和[系列]创建此列表。然后,同步对数值和索引进行排序,即使用相同的Sort组件。虽然,这不是asort()所做的,但非常接近。

有更好的方法吗?在更少的线路中?也许内置方法?一种有效的方式可以优先于更少的线路。

由于

2 个答案:

答案 0 :(得分:4)

PHP和Python之间的主要区别在于PHP数组既是关联的又是有序的,而在Python中,您可以拥有有序 list associative dict,但不能同时存在于一个数据结构中。*

* OrderedDictdict开始变得有序,但让我们坚持原语。

所以从根本上说,你需要考虑不同的数据结构。执行此操作的典型方法是使用元组列表,其中一个元组值表示以前的索引,另一个值表示前一个值:

[(0, 'foo'), (1, 'bar'), ...]

您可以使用enumerate从正常列表中找到它:

l = list(enumerate(my_list))  # ['foo', 'bar'] → [(0, 'foo'), (1, 'bar')]

您可以在此过程中对其进行排序:

l = sorted(enumerate(my_list), key=lambda i: i[1])  # → [(1, 'bar'), (0, 'foo')]

这里lambda i: i[1]只是按第二个元组值排序,即你以前的值。为简洁起见,您可以使用itemgetter(1)模块中的operator替换它,或根据您的排序条件进行调整。

如果要再次将其转换为关联数据结构,请使用OrderedDict

from collections import OrderedDict
from operator import itemgetter

l = OrderedDict(sorted(enumerate(my_list), key=itemgetter(1)))

答案 1 :(得分:1)

首先,将原始值连接到其索引列表。然后对其进行排序,原始索引将附加到新的排序值。最后解压缩它们以获得两个列表。

i_xs                 = [(x, i) for (i, x) in enumerate(xs)]
s                    = sorted(i_xs)
sorted_xs, index_lst = unzip(s)

使用此

def unzip(ls):
    if isinstance(ls, list):
        if not ls:
            return [], []
        else:
            xs, ys = zip(*ls)

        return list(xs), list(ys)
    else:
        raise TypeError

实施例。在:

[34, 23424, 1212, -2324, 34353]

输出:

[-2324, 34, 1212, 23424, 34353]

[3, 0, 2, 1, 4]