Python:使用自定义比较器对字典数组进行排序?

Python:使用自定义比较器对字典数组进行排序?,python,Python,我有以下Python字典数组: myarr = [ { 'name': 'Richard', 'rank': 1 }, { 'name': 'Reuben', 'rank': 4 }, { 'name': 'Reece', 'rank': 0 }, { 'name': 'Rohan', 'rank': 3 }, { 'name': 'Ralph', 'rank': 2 }, { 'name': 'Raphael', 'rank': 0 }, { 'name': 'Robin', 'rank':

我有以下Python字典数组:

myarr = [ { 'name': 'Richard', 'rank': 1 },
{ 'name': 'Reuben', 'rank': 4 },
{ 'name': 'Reece', 'rank': 0 },
{ 'name': 'Rohan', 'rank': 3 },
{ 'name': 'Ralph', 'rank': 2 },
{ 'name': 'Raphael', 'rank': 0 },
{ 'name': 'Robin', 'rank': 0 } ]
我想按秩值排序,顺序如下:1-2-3-4-0-0-0

如果我尝试:

sorted_master_list = sorted(myarr, key=itemgetter('rank'))
然后列表按0-0-0-1-2-3-4的顺序排序

如何定义自定义比较器函数以将零推到列表底部?我想知道我是否可以用像这样的东西

只需传递给“key”任意函数或可调用对象- 这就是它所需要的
itemgetter
恰好就是这样一个函数——但它可以工作 对于您编写的任何函数,它只需接受单个参数作为输入,然后返回 一个可以直接实现你想要的顺序的对象

在这种情况下:

def key_func(item):
   return item["rank"] if item["rank"] != 0 else -100000

sorted_master_list = sorted(myarr, key=key_func)

(也可以编写为lambda表达式)

您可以使用key param中的函数:

对于ass排序:

sorted_master_list = sorted(myarr, key=lambda x: x.get('rank'))
或描述:

sorted_master_list = sorted(myarr, key=lambda x: -x.get('rank'))
您也可以在此处阅读有关排序函数的内容

选项1:

key=lambda d:(d['rank']==0, d['rank'])
备选案文2:

key=lambda d:d['rank'] if d['rank']!=0 else float('inf')
演示:

“我想按排名值排序,顺序如下:1-2-3-4-0-0-0。”——原始海报


补充意见:


“请你向我(一个Python新手)解释一下它在做什么?我可以看到它是一个lambda,我知道它是一个匿名函数:括号中的位是什么?”——OP评论

索引/切片表示法

itemgetter('rank')
lambda x:x['rank']
与函数相同:

def getRank(myDict):
    return myDict['rank']
def dict_by_values(d):
    return [ x[1] for x in sorted([(v,k) for k,v in d.items()])]
[…]
称为索引/切片表示法,另请注意,
someArray[n]
是许多编程语言中用于索引的常用表示法,但可能不支持形式为
[start:end]
[start:end:step]
的切片

key=
vs
cmp=
vs富比较

至于正在发生的事情,有两种常见的方法来指定排序算法的工作方式:一种是使用
函数,另一种是使用
cmp
函数(现在在python中已被弃用,但用途更广)。而
cmp
函数允许您任意指定两个元素的比较方式(输入:
a
b
;输出:
ab
a==b
)。虽然合法,但它并没有给我们带来什么好处(我们不得不以一种笨拙的方式复制代码),关键函数更适合您的情况。(有关如何以优雅但可能过度的方式隐式定义
cmp=
,请参阅“对象丰富比较”)

实现您的关键功能


不幸的是,0是整数的一个元素,因此具有自然顺序:0通常<1,2,3。。。因此,如果我们想强加一个额外的规则,我们需要在“更高级别”上对列表进行排序。我们通过将键设为一个元组来实现这一点:元组首先按第一个元素排序,然后按第二个元素排序。真的总是在假的后面排序,所以所有的真都会在假的后面排序;然后,它们将按正常方式排序:
(True,1)一种黑客方式是:

sorted_master_list = sorted(myarr, key=lambda x: 99999 if x['rank'] == 0 else x['rank'])
如果你知道自己的最高等级,这项功能相当有效。

试试看 排序的\u master\u list=sorted(myarr,key=itemgetter('rank'),reverse=True)

 sortedlist = sorted([x for x in myarr if x['rank']], key=lambda x: x['rank']) + [x for x in myarr if not x['rank']]

我想它可能会被压缩。

我更倾向于创建一个比较函数来处理“0”,特别是:

def compare(x,y):
    if x == y:
        return 0
    elif x == 0:
        return 1
    elif y == 0:
        return -1
    else:
        return cmp(x,y)

sorted(myarr, cmp=lambda x,y: compare(x,y), key=lambda x:x['rank'])

但是,自定义比较函数会有性能损失。

这里的myarr绑定看起来不像是有效的Python代码(并且不会在我的解释器会话中执行)

将其转化为:

myarr = {
    'Richard': 1,
    'Reuben': 4,
    'Reece': 0,
    'Rohan': 3,
    'Ralph': 2,
    'Raphael': 0,
    'Robin': 0 }
给了我一些答案

在Python中进行自定义排序的推荐方法是使用DSU(装饰、排序、取消装饰)模式。 如果要按值对字典排序,则如下所示:

keys_sorted_by_val = [ x[1] for x in sorted([(v,k) for k,v in myarr.items()])]
…其中,
(v,k)表示myarr.items()中的k,v()
装饰的表达式;
排序()
显然是排序,外部
x[1]表示x in…
是最后的取消装饰步骤

显然,这似乎是一个非常常见的要求,可能需要将其封装到函数中:

def getRank(myDict):
    return myDict['rank']
def dict_by_values(d):
    return [ x[1] for x in sorted([(v,k) for k,v in d.items()])]
如果您有一组要按某个属性排序的对象实例,则可以使用如下方式:

def sort_by_attr(attr, coll):
    results = list()
    for each in coll:
        assert hasattr(each, attr)
        results.append((getattr(each, attr), each))
    results.sort()
    return [x[1] for x in results]
class NameRanking(object):
    def __init__(self, name, rank):
        self.name = name
        self.rank = rank
    def __repr__(self):
        return "%s: %s, %s" %(self.__class__, self.name, self.rank)
因此,如果我们创建了一个类来表示您的姓名/等级数据,如下所示:

def sort_by_attr(attr, coll):
    results = list()
    for each in coll:
        assert hasattr(each, attr)
        results.append((getattr(each, attr), each))
    results.sort()
    return [x[1] for x in results]
class NameRanking(object):
    def __init__(self, name, rank):
        self.name = name
        self.rank = rank
    def __repr__(self):
        return "%s: %s, %s" %(self.__class__, self.name, self.rank)
…并使用
myarr
实例化一个列表:

name_排名=[myarr.items()中k,v的名称排名(k,v)]

…然后我们可以使用以下方法获得该文件的排序副本:

names_rankings_by_rank = sort_by_attr('rank', name_rankings)

(是的,
assert
在这里不是一个好主意;您可以在这里放入自己的异常处理或根据应用程序抛出代码)。

这不起作用。
itemgetter()
返回一个函数。当您已经使用lambda时,只需使用
x['rank']
-无论如何,您都失去了使用
itemgetter的性能优势。请您向我(Python新手)解释一下它在做什么?我可以看到它是一个lambda,我知道它是一个匿名函数:括号中的位是什么?@Richard:当然=)我很乐意在我的回答中解释一下,这样每个人都能理解。因为你建议采用股票标准的升序或降序排序,而OP想要一些稍微不同的东西(正常的排序顺序,除了零秩元素的排序不同)在发布一般答案之前,您需要阅读并理解原始问题。这将给出
4,3,2,1,0,0,0
的顺序。OP需要
1,2,3,4,0,0,0
。这是
cmp
解决方案。我喜欢结合使用
key=
cmp=
作为对python中
排序的
参数工作方式的优雅利用。在英语中,这表示“
按等级左右比较元素:如果它们的等级相等,则它们相等,否则