解决这个问题的一种经典方法是使用“装饰、排序、取消装饰”习惯用法,使用 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(*...)
当输入为空时转置失败。如果您的输入可能为空,您将必须单独处理这种情况。