python - 给定并行列表,如何在对一个列表进行排序的同时以相同的方式排列(重新排列)另一个列表?

标签 python list sorting

假设我有:

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

调用list1.sort()会对它进行排序,结果是[1, 1, 2, 3, 4]。但是,我可以让 list2 与其同步重新排列,以获得这样的结果吗?

list1 = [1, 1, 2, 3, 4]
list2 = ['one', 'one2', 'two', 'three', 'four']
<小时/>

有时,人们 phrase the problem differently :给定两个列表,他们希望使用一个列表来确定另一个列表的排序顺序 - 即按照 list1 中相应值描述的顺序对 list2 进行排序。诀窍在于,这相当于对“键”值进行排序 (list1),然后以相同的方式重新排列list2。换句话说,正是这里所描述的。不过,其他问题的一些答案之后会丢弃“排序键”。

另请参阅:How can I sort a list, according to where its elements appear in another list? - 这是人们希望“基于”另一个列表对一个列表进行排序的另一种常见方式。在尝试关闭重复问题之前,请特别注意检查OP到底想要什么。关键线索:列表的长度是否需要相同?

最佳答案

解决这个问题的一个经典方法是使用“装饰、排序、取消装饰”习惯用法,使用 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 指出的那样,JSF's suggestion仍然快一点,但可能只会快一点,因为 Python 使用 very same DSU idiom internally对于所有基于键的排序。它只是发生在更接近裸机的地方。 (这显示了 zip 例程的优化程度!)

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

<小时/>

请注意,当 list1 的元素相等时,此方法最终将比较 list2 的元素。如果 list2 的元素不支持比较,或者比较时不生成 bool 值(例如,如果 list2 是 NumPy 数组的列表),则此操作将会失败,如果 list2 的元素比较起来非常昂贵,那么最好还是避免比较。

在这种情况下,您可以按照 jfs 的答案中的建议对索引进行排序,或者您可以为排序提供一个关键函数,以避免比较 list2 的元素:

result1, result2 = zip(*sorted(zip(list1, list2), key=lambda x: x[0]))

此外,当输入为空时,使用 zip(*...) 作为转置会失败。如果您的输入可能为空,您将必须单独处理这种情况。

关于python - 给定并行列表,如何在对一个列表进行排序的同时以相同的方式排列(重新排列)另一个列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57944828/

相关文章:

python - 使用二元运算符时调用的函数,python

python - TensorFlow:记住以前时代的重量

python - 什么时候链接列表优先于列表?

java - Java ArrayList中的比较和条件检查

javascript - 查找对象的最大和最小内部数组

c++ - 在模板函数中使用 STL Sort?

javascript - 同位素排序不起作用

python - Windows 自动化 : Emulating menu item events

python - 如何提取扩展名并保存而不重复?

java - 这两个通用函数之间的区别