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

2023-12-02

假设我有:

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

Calling list1.sort()将对它进行排序,结果是[1, 1, 2, 3, 4]。然而,我能得到list2与此同步重新排列,以获得这样的结果?

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

Sometimes, people phrase the problem differently: given two lists, they would like to use one to determine the sort order for the other - i.e., sort list2 in the order described by the corresponding values in list1. The trick is that this is equivalent to sorting the "key" values (list1), and then rearranging list2 in the same way. In other words, exactly what is described here. Some answers for the other question, though, discard the "sorted keys" afterwards.

See also: How can I sort a list, according to where its elements appear in another list? - this is another common way that people want to sort one list "based on" another. Before attempting to close duplicate questions, take special care to check exactly what the OP wants. A key clue: do the lists need to be the same length?


解决这个问题的一种经典方法是使用“装饰、排序、取消装饰”习惯用法,使用 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的建议仍然快一点,但可能只会快一点,因为 Python 使用内部的 DSU 习惯用法非常相同对于所有基于键的排序。它只是发生在更接近裸机的地方。 (这表明优化得有多好zip惯例是!)

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


请注意,当元素list1是相等的,这种方法最终将比较元素list2。如果元素为list2不支持比较,或者比较时不生成布尔值(例如,如果list2是 NumPy 数组的列表),这将失败,并且如果list2比较起来非常昂贵,无论如何最好避免比较。

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

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐