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

2024-09-24 22:28:29 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有两个列表:

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

如果我运行list1.sort(),它会将它排序为[1,1,2,3,4],但是有没有办法让list2也同步(所以我可以说项目4属于'three')?因此,预期产出为:

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

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

基本上,这个程序的本质是,数据以随机顺序出现(如上所述),我需要对其进行排序、处理,然后发送结果(顺序不重要,但用户需要知道哪个结果属于哪个键)。我想先把它放在字典里,然后把列表排序,但如果不保持顺序,我就无法区分列表中具有相同值的项目(这可能会影响将结果传达给用户)。因此,理想情况下,一旦我得到了列表,我宁愿想办法将两个列表排序在一起。这可能吗


Tags: 数据项目程序列表字典排序顺序one
3条回答

解决此问题的一个经典方法是使用“装饰、排序、取消装饰”习惯用法,使用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的方法更灵活,可读性更强,所以我更喜欢它

我已经使用senderle给出的答案很久了,直到我发现np.argsort。 下面是它的工作原理

# idx works on np.array and not lists.
list1 = np.array([3,2,4,1])
list2 = np.array(["three","two","four","one"])
idx   = np.argsort(list1)

list1 = np.array(list1)[idx]
list2 = np.array(list2)[idx]

我觉得这个解决方案更直观,而且效果非常好。表演:

def sorting(l1, l2):
    # l1 and l2 has to be numpy arrays
    idx = np.argsort(l1)
    return l1[idx], l2[idx]

# list1 and list2 are np.arrays here...
%timeit sorting(list1, list2)
100000 loops, best of 3: 3.53 us per loop

# This works best when the lists are NOT np.array
%timeit zip(*sorted(zip(list1, list2)))
100000 loops, best of 3: 2.41 us per loop

# 0.01us better for np.array (I think this is negligible)
%timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100000 loops, best for 3 loops: 1.96 us per loop

尽管np.argsort不是最快的,但我发现它更容易使用

可以使用值作为键对索引进行排序:

indexes = range(len(list1))
indexes.sort(key=list1.__getitem__)

要获取给定已排序索引的已排序列表,请执行以下操作:

sorted_list1 = map(list1.__getitem__, indexes)
sorted_list2 = map(list2.__getitem__, indexes)

在您的情况下,不应该有list1list2,而应该有一个对的列表:

data = [(3, 'three'), (2, 'two'), (4, 'four'), (1, 'one'), (1, 'one2')]

它很容易创造;在Python中很容易排序:

data.sort() # sort using a pair as a key

仅按第一个值排序:

data.sort(key=lambda pair: pair[0])

相关问题 更多 >