我有dict()
名为twitter_users
,其中包含TwitterUser
个对象作为值。我希望这些对象按字段mentioned
排序。但是,使用sorted()
并不像我预期的那样有效。我提供了一个lambda
函数,用于确定是否更频繁地提及用户a
或用户b
。
srt = sorted(twitter_users.values(),
cmp=(lambda a,b:
True if a.mentioned > b.mentioned else False))
for s in srt:
print s.mentioned
不幸的是,这不起作用且列表srt
没有以任何方式排序。
我该如何做到这一点?
答案 0 :(得分:10)
cmp
函数应该返回一个整数,0
相等,1
或更高,a
应该在b
和-1
之后如果它们的顺序相反,则降低。
您将返回False
和True
。因为Python布尔类型是int
的子类,所以当解释为整数时,这些对象具有值0
和1
。你永远不会返回-1
,所以你混淆了排序算法;你告诉它a
和b
的顺序要么总是等于'或者a
应始于b
之前。但是排序算法有时会要求交换a
和b
,在这种情况下你给它提供了相互矛盾的信息!
请注意,你的表达相当冗长; True if a.mentioned > b.mentioned else False
可以简化为a.mentioned > b.mentioned
; >
运算符已生成True
或False
。使用简单的整数,您可以看到这不会产生预期的结果:
>>> sorted([4, 2, 5, 3, 8], cmp=lambda a, b: a > b)
[4, 2, 5, 3, 8]
实际返回-1
,0
或1
确实有效:
>>> sorted([4, 2, 5, 3, 8], cmp=lambda a, b: 1 if a > b else 0 if a == b else -1)
[2, 3, 4, 5, 8]
或者代替这种冗长的表达式,只需使用内置的cmp()
function;对于你的情况,你可以这样使用:
srt = sorted(twitter_users.values(), cmp=lambda a, b: cmp(a.mentioned, b.mentioned))
但你根本不应该使用cmp
;有一个更简单(更有效)的选择。只需使用key
函数,它只返回mentioned
属性:
srt = sorted(twitter_users.values(), key=lambda v: v.mentioned)
key
函数生成实际排序的值;此函数用于生成Schwartzian transform。这种转换更有效,因为它只被称为O(n)次,而cmp
函数被称为O(n log n)次。
因为您只访问属性而不是lambda
,所以您可以使用operator.attrgetter()
object为您执行属性提取:
from operator import attrgetter
srt = sorted(twitter_users.values(), key=attrgetter('mentioned'))