一尘不染

如何以完全相同的方式对两个列表(相互引用)进行排序

python

说我有两个清单:

list1 = [3, 2, 4, 1, 1]
list2 = ['three', 'two', 'four', 'one', 'one2']

如果我运行list1.sort(),它将对其进行排序,[1,1,2,3,4]但是还有没有一种list2同步的方法(因此我可以说item4属于'three')?因此,预期输出为:

list1 = [1, 1, 2, 3, 4]
list2 = ['one', 'one2', 'two', 'three', 'four']

我的问题是我有一个非常复杂的程序,可以很好地处理列表,但是我有点需要开始引用一些数据。我知道这对字典来说是一个完美的情况,但是我在处理过程中尽量避免使用字典,因为我确实需要对键值进行排序(如果必须使用字典,我知道如何使用它们)。

基本上,该程序的本质是,数据按随机顺序出现(如上),我需要对其进行排序,处理然后发送结果(顺序无关紧要,但是用户需要知道哪个结果属于哪个结果)键)。我考虑过先将其放入字典中,然后再对列表进行排序,但是如果不保持顺序(如果将结果传达给用户,可能会产生影响),我将无法区分具有相同值的项。因此,理想情况下,一旦获得列表,我宁愿想出一种将两个列表排序在一起的方法。这可能吗?


阅读 159

收藏
2020-12-20

共1个答案

一尘不染

解决此问题的一种经典方法是使用“装饰,排序,未装饰”习惯用法,使用python的内置zip函数特别简单:

>>> list1 = [3,2,4,1, 1]
>>> list2 = ['three', 'two', 'four', 'one', 'one2']
>>> list1, list2 = zip(*sorted(zip(list1, list2)))
>>> list1
(1, 1, 2, 3, 4)
>>> list2 
('one', 'one2', 'two', 'three', 'four')

这些当然不再是列表,但是如果需要的话,很容易纠正:

>>> list1, list2 = (list(t) for t in zip(*sorted(zip(list1, list2))))
>>> list1
[1, 1, 2, 3, 4]
>>> list2
['one', 'one2', 'two', 'three', 'four']

值得一提的是,以上可能会为简洁而牺牲速度。就地版本,占用3行,在我的机器上,对于较小的列表来说,快了一点:

>>> %timeit zip(*sorted(zip(list1, list2)))
100000 loops, best of 3: 3.3 us per loop
>>> %timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100000 loops, best of 3: 2.84 us per loop

另一方面,对于较大的列表,单行版本可能会更快:

>>> %timeit zip(*sorted(zip(list1, list2)))
100 loops, best of 3: 8.09 ms per loop
>>> %timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100 loops, best of 3: 8.51 ms per loop

正如Quantum7指出的那样,[SF的建仍然要快一些,但可能只会更快一些,因为Python内部在所有基于键的排序中使用了完全相同的DSU习惯用法。它只是在接近裸机的地方发生。(这表明zip例程的优化程度如何!)

我认为zip基于方法的灵活性更高,可读性更好,所以我更喜欢它。

2020-12-20