根据单个列表的排序对多个列表进行排序

4 投票
2 回答
8265 浏览
提问于 2025-04-17 20:12

我是一名刚接触Python的新手,遇到了一个看似简单的问题,现在想找出最有效的解决办法。我有5个列表,如下所示:

a,b,c,d,score

这些列表的大小都是一样的(在我的例子中是500)。其中,a,b,c,d是字符串列表,而score是一个整数列表。

我想做的是根据score的升序或降序来对a,b,c,d进行排序。具体来说,我想先把score按降序排列,然后再根据这个排序结果,按照相同的顺序对a,b,c,d中的对应元素进行排序。

我在考虑使用enumerate来实现这个目标,但我在想是否可以用itertools来让这个过程更快、更高效。

如果有人能给我一些指导,我将非常感激。如果这个问题太基础了,我也很抱歉。

2 个回答

3

如果你在做很多数字计算或者数组处理,建议你看看 numpy。用 numpy 数组可以很简单地解决这个问题:

In [1]: import numpy as np
In [2]: a = ['hi','hello']
In [3]: b = ['alice','bob']
In [4]: c = ['foo','bar']
In [5]: d = ['spam','eggs']
In [6]: score = [42,17]

接下来,你可以创建一个包含元组的列表,格式是 (a,b,c,d,score),并且为每个元组设置数据类型 (str,str,str,str,int),你甚至可以给它们起名字 ('a','b','c','d','score'),这样以后就能方便地访问它们:

In [7]: data = np.array(zip(a,b,c,d,score),
   ...:         dtype = [('a','S5'),('b','S5'),('c','S5'),('d','S5'),('score',int)]
   ...:     )

In [8]: data
Out[8]: 
array([('hi', 'alice', 'foo', 'spam', 42),
       ('hello', 'bob', 'bar', 'eggs', 17)], 
      dtype=[('a', 'S5'), ('b', 'S5'), ('c', 'S5'), ('d', 'S5'), ('score', '<i8')])

这个数组的好处是,你可以通过名字来访问所有的“列表”(字段):

In [9]: data['a']
Out[9]: 
array(['hi', 'hello'], 
      dtype='|S5')

In [10]: data['score']
Out[10]: array([42, 17])

要排序的话,只需要告诉它你想按哪个字段排序就可以了:

In [11]: sdata = np.sort(data, order='score')

In [12]: sdata
Out[12]: 
array([('hello', 'bob', 'bar', 'eggs', 17),
       ('hi', 'alice', 'foo', 'spam', 42)], 
      dtype=[('a', 'S5'), ('b', 'S5'), ('c', 'S5'), ('d', 'S5'), ('score', '<i8')])

In [13]: sdata['b']
Out[13]: 
array(['bob', 'alice'], 
      dtype='|S5')
8
sorted_lists = sorted(izip(a, b, c, d, score), reverse=True, key=lambda x: x[4])
a, b, c, d, score = [[x[i] for x in sorted_lists] for i in range(5)]

在第一步中,我们把多个列表“拉链”在一起。这个过程是把每个列表的第一个元素拿出来,放进一个叫做元组的东西里,然后把这个元组加到一个新的列表中。接着,我们对每个列表的第二个元素做同样的事情,依此类推。之后,我们根据元组中的第五个元素来给这个元组列表排序(这个排序是通过传给key参数的匿名函数来实现的)。我们设置reverse=True,这样列表就会按降序排列。

在第二步中,我们使用一些嵌套的列表推导和元组拆包来把列表分开。我们创建一个新的列表,其中每个内部列表包含sorted_lists中每个元组的所有第一个元素。你可以用一行代码来完成这个操作,如下所示,但我觉得分成两部分可能会更清晰:

a, b, c, d, score = izip(*sorted(izip(a, b, c, d, score), reverse=True,
                         key=lambda x: x[4]))

这里有一个通用的函数,它返回一个元组列表,这些元组就是排序后的列表:

def sort_lists_by(lists, key_list=0, desc=False):
    return izip(*sorted(izip(*lists), reverse=desc,
                 key=lambda x: x[key_list]))

撰写回答