根据单个列表的排序对多个列表进行排序
我是一名刚接触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 个回答
如果你在做很多数字计算或者数组处理,建议你看看 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')
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]))