Python:使用自定义比较器对字典数组进行排序?
我有以下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':
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=
vscmp=
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中排序的参数工作方式的优雅利用。在英语中,这表示“按等级左右比较元素:如果它们的等级相等,则它们相等,否则