按多个属性对列表进行排序?

hea*_*che 398 python sorting

我有一份清单清单:

[[12, 'tall', 'blue', 1],
[2, 'short', 'red', 9],
[4, 'tall', 'blue', 13]]
Run Code Online (Sandbox Code Playgroud)

如果我想按一个元素排序,比如高/短元素,我可以通过s = sorted(s, key = itemgetter(1)).

如果我想作为排序依据两个高大/ short和颜色,我可以为每个元素做排序两次,一次,但有一个更快的方法?

Mar*_*ers 673

键可以是返回元组的函数:

s = sorted(s, key = lambda x: (x[1], x[2]))
Run Code Online (Sandbox Code Playgroud)

或者你可以实现相同的使用itemgetter(更快,避免Python函数调用):

import operator
s = sorted(s, key = operator.itemgetter(1, 2))
Run Code Online (Sandbox Code Playgroud)

请注意,在这里您可以使用sort而不是使用sorted然后重新分配:

s.sort(key = operator.itemgetter(1, 2))
Run Code Online (Sandbox Code Playgroud)

  • 如果我想将`revrse = True`仅应用于`x [1]`那可能怎么样? (68认同)
  • @Amyth或其他选项,如果key是数字,为了使其反转,你可以用`-1`复数. (45认同)
  • @ emose,@ Amyth,只能反转一个属性,你可以排序两次:首先是次要的`s = sorted(s,key = operator.itemgetter(2))`然后是主要的`s = sorted(s, key = operator.itemgetter(1),reverse = True)`不理想,但有效. (26认同)
  • 为了完成时间:对我来说,每个循环首先给出6 us,每循环给第二个4.4 us (19认同)
  • 有没有办法对第一个升序和第二个降序进行排序?(假设两个属性都是字符串,所以没有像为整数添加`-`那样的黑客攻击) (9认同)
  • @moose:不幸的是我不认为有一种非黑客方式.文档中提出的方法是使用排序稳定的属性进行两次排序.有关详细信息,请参阅[此处](http://docs.python.org/2/howto/sorting.html#sort-stability-and-complex-sorts). (4认同)
  • 你每天学习新的东西!你知道这在计算上是否比以前的方法更快?或者它只是在后台做同样的事情? (2认同)
  • @headache:我不知道哪个更快 - 我怀疑它们差不多.如果您感兴趣,可以使用`timeit`模块来测量两者的性能. (2认同)
  • @eyildiz 乘以 -1 不适用于字符串数据 (2认同)
  • 有人可以解释一下,与使用“lambda”相比,使用“operator”模块中的函数创建的可调用函数如何避免函数调用?我的意思是使用像“operator.itemgetter”这样的东西仍然是一个函数调用,对吧? (2认同)

Cli*_*ord 31

我不确定这是否是最pythonic方法...我有一个元组列表,需要按降序整数值排序第一,按字母顺序排序第二.这需要反转整数排序,但不是按字母顺序排序.这是我的解决方案:(在考试中即时通讯,我甚至不知道你可以'嵌套'排序功能)

a = [('Al', 2),('Bill', 1),('Carol', 2), ('Abel', 3), ('Zeke', 2), ('Chris', 1)]  
b = sorted(sorted(a, key = lambda x : x[0]), key = lambda x : x[1], reverse = True)  
print(b)  
[('Abel', 3), ('Al', 2), ('Carol', 2), ('Zeke', 2), ('Bill', 1), ('Chris', 1)]
Run Code Online (Sandbox Code Playgroud)

  • 因为2nd是一个数字,所以它的工作方式就像`b = sorted(a,key = lambda x:( - x [1],x [0]))`这在哪个条件首先应用时更加明显.至于效率,我不确定,有人需要时间. (10认同)

don*_*don 15

几年迟到了,但我想这两种排序2个标准使用reverse=True。如果其他人想知道如何,您可以将您的标准(函数)括在括号中:

s = sorted(my_list, key=lambda i: ( criteria_1(i), criteria_2(i) ), reverse=True)
Run Code Online (Sandbox Code Playgroud)


UpA*_*dam 7

看来您可以使用 alist而不是 a tuple。我认为当您获取属性而不是列表/元组的“魔术索引”时,这变得更加重要。

就我而言,我想按类的多个属性进行排序,其中传入的键是字符串。我需要在不同的地方进行不同的排序,并且我希望客户端与之交互的父类有一个通用的默认排序;只需要在我真正“需要”时覆盖“排序键”,而且还可以将它们存储为类可以共享的列表

所以首先我定义了一个辅助方法

def attr_sort(self, attrs=['someAttributeString']:
  '''helper to sort by the attributes named by strings of attrs in order'''
  return lambda k: [ getattr(k, attr) for attr in attrs ]
Run Code Online (Sandbox Code Playgroud)

然后使用它

# would defined elsewhere but showing here for consiseness
self.SortListA = ['attrA', 'attrB']
self.SortListB = ['attrC', 'attrA']
records = .... #list of my objects to sort
records.sort(key=self.attr_sort(attrs=self.SortListA))
# perhaps later nearby or in another function
more_records = .... #another list
more_records.sort(key=self.attr_sort(attrs=self.SortListB))
Run Code Online (Sandbox Code Playgroud)

这将使用生成的 lambda 函数对列表进行排序object.attrA,然后object.attrB假设object有一个对应于提供的字符串名称的 getter。第二种情况将按object.attrCthen排序object.attrA

这也允许您潜在地公开向外排序选项以供消费者、单元测试共享,或者让他们也许告诉您他们希望如何对您的 api 中的某些操作进行排序,只需给您一个列表而不是将它们耦合到您的后端实现。


Gol*_*ion 7

将列表列表转换为元组列表,然后按多个字段对元组进行排序。

 data=[[12, 'tall', 'blue', 1],[2, 'short', 'red', 9],[4, 'tall', 'blue', 13]]

 data=[tuple(x) for x in data]
 result = sorted(data, key = lambda x: (x[1], x[2]))
 print(result)
Run Code Online (Sandbox Code Playgroud)

输出:

 [(2, 'short', 'red', 9), (12, 'tall', 'blue', 1), (4, 'tall', 'blue', 13)]
Run Code Online (Sandbox Code Playgroud)