在Python中,基于单个列表的排序,可以对多个列表进行排序。

4

我是一名Python新手,遇到了一个相当简单的问题 - 我正在寻找最有效的解决方法。我有5个列表,如下所示:

a,b,c,d,score

以上列表中所有元素大小均相等(在我的情况下为500)。a、b、c、d是字符串列表,score是整数列表。
我想要做的是根据升序或降序排序score来对a、b、c、d进行排序。因此,我首先想要按照降序模式对score进行排序,然后基于排好序的score列表(以相同的顺序)对a、b、c、d进行排序。
我考虑使用枚举来实现这一点,但我想知道itertools是否可以用于使它更快,更高效。
如果你能提供任何关于如何实现这个目标的指导,那将不胜感激!如果这是一个基础问题,请原谅。

1
请参考此处类似的问题:https://dev59.com/PGw15IYBdhLWcg3wbbNx - alecxe
这是另一个与https://dev59.com/Amkw5IYBdhLWcg3w8fFJ相同的问题。但是,如果列表很大且使用的是Python == 2,则it.izip比仅使用zip更好。 - georg
2个回答

7
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]))

编辑以添加一个通用函数。 range(5)只是表示子列表中每个元素的索引,这样我们就可以在将它们组合在一起后将每个子列表分开。 x [4]仅表示我们正在排序所有其他列表的列表。在通用函数中,这些将被替换。 - EML
@EML:非常感谢你提供的帮助。我觉得我需要一些时间才能完全掌握它,但我理解了你的排序思路。我会逐步尝试并更清楚地理解它。再次感谢,我接受了你的答案。 - AJW
1
izip 的输出与 zip 基本相同,但它不是为整个要构建的组合列表分配大量新内存,而是创建一个“生成器”,该生成器基本上一次输出一个项目,尽可能地回收内存。 它使用的内存要少得多,并且在大多数情况下更快。 这里有一个由 Ray Hettinger 提供的演讲,他在其中简要提到了这一点:http://www.youtube.com/watch?v=OSGv2VnC0go - EML
我实际上打错了字,忘记设置 reverse=desc。所以你并不是傻的 - 只是注意到了我的错误。我已经修复了它。我在参数中放置了 desc=False,这样当调用这个通用函数时,你可以选择是按降序还是升序排序。对于 sorted 和我们的新 sort_lists_by 之间的默认行为相同,这更有意义。 - EML
1
好的,明白了。我假设你要把它们作为列表传递,像[a,b,c,d,score] - AJW
显示剩余6条评论

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),并使用dtype(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')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接