按多个属性排序列表?

我有一个列表列表:

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

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

如果我想按这两个高/短和颜色排序,我可以做两次排序,每个元素一次,但有没有更快的方法?

497997 次浏览

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

s = sorted(s, key = lambda x: (x[1], x[2]))

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

import operator
s = sorted(s, key = operator.itemgetter(1, 2))

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

s.sort(key = operator.itemgetter(1, 2))

我不确定这是否是最python的方法… 我有一个元组列表,第一个需要按整数值降序排序,第二个需要按字母顺序排序。这需要反转整数排序,但不需要反转字母排序。这是我的解决方案:(顺便说一句,在考试中,我甚至不知道你可以“嵌套”排序函数)

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)]
看起来你可以使用list而不是tuple。 我认为,当你抓取属性而不是列表/元组的“魔法索引”时,这变得更加重要。< / p >

在我的例子中,我想按类的多个属性排序,其中传入的键是字符串。我需要在不同的地方进行不同的排序,并且我想为客户端交互的父类提供一个通用的默认排序;只需要在我真的“需要”的时候重写“排序键”,但在某种程度上,我可以将它们存储为类可以共享的列表

首先我定义了一个helper方法

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 ]

然后使用它

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

这将使用生成的lambda函数根据object.attrAobject.attrB对列表进行排序,假设object有一个与所提供的字符串名称对应的getter。第二种情况是按object.attrCobject.attrA排序。

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

这里有一种方法:你基本上重写你的排序函数来获得一个排序函数的列表,每个排序函数比较你想测试的属性,在每个排序测试中,你看看cmp函数是否返回一个非0的返回值,如果是,就中断并发送返回值。 你可以通过调用Lambda列表中的函数的Lambda来调用它

它的优点是它只对数据进行单遍历,而不像其他方法那样进行前一个排序。另一件事是,它在原地排序,而排序似乎产生了一个副本。

我用它来写一个排序函数,它对每个对象在一个组中的类列表进行排序,并有一个评分函数,但你可以添加任何属性列表。 注意,lambda调用setter的用法与un-lambda类似,但略显粗陋。 排序部分对列表数组不起作用,但排序部分可以
#First, here's  a pure list version
my_sortLambdaLst = [lambda x,y:cmp(x[0], y[0]), lambda x,y:cmp(x[1], y[1])]
def multi_attribute_sort(x,y):
r = 0
for l in my_sortLambdaLst:
r = l(x,y)
if r!=0: return r #keep looping till you see a difference
return r


Lst = [(4, 2.0), (4, 0.01), (4, 0.9), (4, 0.999),(4, 0.2), (1, 2.0), (1, 0.01), (1, 0.9), (1, 0.999), (1, 0.2) ]
Lst.sort(lambda x,y:multi_attribute_sort(x,y)) #The Lambda of the Lambda
for rec in Lst: print str(rec)

下面是一种对对象列表进行排序的方法

class probe:
def __init__(self, group, score):
self.group = group
self.score = score
self.rank =-1
def set_rank(self, r):
self.rank = r
def __str__(self):
return '\t'.join([str(self.group), str(self.score), str(self.rank)])




def RankLst(inLst, group_lambda= lambda x:x.group, sortLambdaLst = [lambda x,y:cmp(x.group, y.group), lambda x,y:cmp(x.score, y.score)], SetRank_Lambda = lambda x, rank:x.set_rank(rank)):
#Inner function is the only way (I could think of) to pass the sortLambdaLst into a sort function
def multi_attribute_sort(x,y):
r = 0
for l in sortLambdaLst:
r = l(x,y)
if r!=0: return r #keep looping till you see a difference
return r


inLst.sort(lambda x,y:multi_attribute_sort(x,y))
#Now Rank your probes
rank = 0
last_group = group_lambda(inLst[0])
for i in range(len(inLst)):
rec = inLst[i]
group = group_lambda(rec)
if last_group == group:
rank+=1
else:
rank=1
last_group = group
SetRank_Lambda(inLst[i], rank) #This is pure evil!! The lambda purists are gnashing their teeth


Lst = [probe(4, 2.0), probe(4, 0.01), probe(4, 0.9), probe(4, 0.999), probe(4, 0.2), probe(1, 2.0), probe(1, 0.01), probe(1, 0.9), probe(1, 0.999), probe(1, 0.2) ]


RankLst(Lst, group_lambda= lambda x:x.group, sortLambdaLst = [lambda x,y:cmp(x.group, y.group), lambda x,y:cmp(x.score, y.score)], SetRank_Lambda = lambda x, rank:x.set_rank(rank))
print '\t'.join(['group', 'score', 'rank'])
for r in Lst: print r

几年后的派对,但我想这两个排序2个标准而且使用reverse=True。如果有人想知道怎么做,你可以把你的标准(函数)包装在括号里:

s = sorted(my_list, key=lambda i: ( criteria_1(i), criteria_2(i) ), reverse=True)

有一个操作员<在列表之间。

[12, 'tall', 'blue', 1] < [4, 'tall', 'blue', 13]

将会给

False

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

 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)

输出:

 [(2, 'short', 'red', 9), (12, 'tall', 'blue', 1), (4, 'tall', 'blue', 13)]