Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 是否按多个属性对列表排序?_Python_Sorting - Fatal编程技术网

Python 是否按多个属性对列表排序?

Python 是否按多个属性对列表排序?,python,sorting,Python,Sorting,我有一份清单: [[12, 'tall', 'blue', 1], [2, 'short', 'red', 9], [4, 'tall', 'blue', 13]] 如果我想按一个元素排序,比如高/短元素,我可以通过s=sorted(s,key=itemgetter(1))来完成 如果我想同时按高/短和颜色进行排序,我可以对每个元素进行两次排序,一次,但有没有更快的方法?键可以是返回元组的函数: s = sorted(s, key = lambda x: (x[1], x[2])) 或者您也

我有一份清单:

[[12, 'tall', 'blue', 1],
[2, 'short', 'red', 9],
[4, 'tall', 'blue', 13]]
如果我想按一个元素排序,比如高/短元素,我可以通过
s=sorted(s,key=itemgetter(1))
来完成


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

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

s = sorted(s, key = lambda x: (x[1], x[2]))
或者您也可以使用
itemgetter
实现同样的效果(这样更快,并且避免了Python函数调用):

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

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

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


似乎可以使用
列表
而不是
元组
。 我认为,当您获取属性而不是列表/元组的“神奇索引”时,这一点变得更加重要

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

所以首先我定义了一个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.attrA
对列表进行排序,然后假设
object.attrB
具有与提供的字符串名称相对应的getter。第二种情况是按
object.attrC
排序,然后按
object.attrA
排序


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

这里有一种方法:您基本上重新编写排序函数,以获取排序函数的列表,每个排序函数比较您想要测试的属性,在每个排序测试中,您都会查看cmp函数是否返回非零返回值(如果是),然后断开并发送返回值。 通过调用Lambda列表中函数的Lambda来调用它

它的优点是,它只通过一次数据,而不像其他方法那样是前一次排序。另一件事是,它在适当的位置排序,而排序似乎是复制

我用它写了一个rank函数,它对类列表进行排序,其中每个对象都在一个组中,并且有一个score函数,但是您可以添加任何属性列表。 请注意,使用lambda调用setter与unlambda类似,但很有技巧。 排名部分不适用于列表数组,但排序部分适用

#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

聚会晚了几年,但我想根据两个标准进行排序使用
reverse=True
。如果其他人想知道如何操作,可以将条件(函数)括在括号中:

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

列表之间有一个运算符<,例如:

[12'高','蓝',1]<[4'高','蓝',13]
将给予

False

从时间上看完整性IT:对于我来说,第一个循环给6个us,第二个循环给4.4个us,有没有办法将第一个循环升序,第二个循环降序?(假设两个属性都是字符串,因此没有像为整数添加
-
这样的黑客)如果我只想将
revrse=True
应用于
x[1]
这可能吗?@moose,@Amyth,要仅反转为一个属性,可以排序两次:首先按次
s=sorted(s,key=operator.itemgetter(2))
然后通过主
s=sorted(s,key=operator.itemgetter(1),reverse=True)
不理想,但有效。@Amyth或另一个选项,如果key是number,要使其反向,可以通过
-1
将其倍数增加。如果使用元组而不是列表,则在运行
排序时,python按条目从左到右排序。也就是说,
sorted([(4,2),(0,3),(0,1)]==[(0,1),(0,3),(4,2)]
。由于第二个是一个数字,它的工作原理类似于
b=sorted(a,key=lambda x:(-x[1],x[0])
,更明显的是在哪个标准上首先应用。至于效率,我不确定,需要有人来计时。干得好。如果属性应该按不同的顺序排序呢?假设attrA应按升序排序,attrB应按降序排序?除此之外还有快速解决方案吗?谢谢@mhn_namak看到哪一种是根据n个标准进行排序的美丽方式,每个标准都是升序或降序的。我们显然对美丽有非常不同的看法。而这是我见过的最有趣的事情。效率是(n*m)的函数,其中m是要排序的属性数,而不仅仅是列表长度的函数。我认为这里的其他答案有更好的解决方案,或者你可以自己编写排序函数,如果你真的需要这样做的话
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
s = sorted(my_list, key=lambda i: ( criteria_1(i), criteria_2(i) ), reverse=True)