我有以下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的顺序对列表进行排序。
如何定义一个自定义比较器函数,将零推到列表的底部?我在想我能不能用点类似methodcaller的东西。
选项1:
选择2:
演示:
其他评论:
索引/切片表示法:
itemgetter('rank')
与lambda x: x['rank']
是相同的,与函数是相同的:[...]
称为索引/切片表示法,请参见Explain Python's slice notation-还要注意someArray[n]
是许多编程语言中用于索引的常用表示法,但可能不支持[start:end]
或[start:end:step]
形式的切片。key=
与cmp=
与丰富比较:至于发生了什么,有两种常用的方法来指定排序算法是如何工作的:一种是使用
key
函数,另一种是使用cmp
函数(现在在python中已弃用,但用途更广)。而cmp
函数允许您任意指定两个元素应该如何比较(输入:a
,b
;输出:a<b
或a>b
或a==b
)。虽然是合法的,但它并没有给我们带来任何好处(我们不得不以一种尴尬的方式复制代码),而且对于您的情况,键函数更自然。(有关如何以优雅但可能过分的方式隐式定义cmp=
,请参阅“对象丰富比较”。)实现关键功能:
不幸的是,0是整数的一个元素,因此具有自然顺序:0通常是<;1,2,3。。。因此,如果我们想强加一个额外的规则,我们需要在“更高的层次”对列表进行排序。为此,我们将键设为元组:元组首先按其第一个元素排序,然后按其第二个元素排序。True总是在False之后排序,因此所有True都将在False之后排序;然后它们将按正常顺序排序:
(True,1)<(True,2)<(True,3)<...
、(False,1)<(False,2)<...
、(False,*)<(True,*)
。另一种选择(选项2)仅仅为rank-0字典分配一个无穷大的值,因为它保证高于任何可能的秩。更一般的替代方案-对象丰富的比较:
更一般的解决方案是创建一个表示记录的类,然后实现} decorator 。这将导致该类的对象在使用比较运算符(例如
__lt__
、__gt__
、__eq__
、__ne__
、__gt__
、__ge__
和所有其他rich comparison operators,或者只实现其中一个和__eq__
,并使用^{x=Record(name='Joe', rank=12)
y=Record(...)
x<y
)时使用自定义逻辑;由于sorted(...)
函数在比较排序中默认使用<
和其他比较运算符,这将使排序时以及在使用<
和其他比较运算符。这可能是过度的,也可能不是过度的,这取决于您的用例。更干净的替代方案-不要用语义重载0:
不过,我应该指出,把0放在1、2、3、4等后面有点人为。这是否合理取决于rank=0是否真的意味着rank=0;如果rank=0真的比rank=1“低”(而rank=1又真的比rank=2“低”)。如果这是真的,那么你的方法是完美的。如果不是这样,那么可以考虑省略
'rank':...
条目,而不是设置'rank':0
。然后您可以使用'rank' in d
按Lev Levitsky的答案排序,或者按:不同方案的方案1:
不同方案的方案2:
侧注:依赖于python中无穷大的存在几乎是一种技巧,使得任何提到的解决方案(元组、对象比较)、Lev的filter-then-concatenate solution,甚至可能是稍微复杂一点的^{} solution (由wilson键入),对其他语言更具通用性。
我更倾向于创建一个比较函数来具体处理“0”:
但是,自定义比较函数有性能损失。
我会的
我想它可能被压缩了。
相关问题 更多 >
编程相关推荐