为什么我的列表没有按预期排序?

时间:2016-01-20 18:35:30

标签: python sorting

我有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没有以任何方式排序。

我该如何做到这一点?

1 个答案:

答案 0 :(得分:10)

cmp函数应该返回一个整数,0相等,1或更高,a应该在b-1之后如果它们的顺序相反,则降低。

您将返回FalseTrue。因为Python布尔类型是int的子类,所以当解释为整数时,这些对象具有值01。你永远不会返回-1,所以你混淆了排序算法;你告诉它ab的顺序要么总是等于'或者a应始于b之前。但是排序算法有时会要求交换ab,在这种情况下你给它提供了相互矛盾的信息!

请注意,你的表达相当冗长; True if a.mentioned > b.mentioned else False可以简化为a.mentioned > b.mentioned; >运算符已生成TrueFalse。使用简单的整数,您可以看到这不会产生预期的结果:

>>> sorted([4, 2, 5, 3, 8], cmp=lambda a, b: a > b)
[4, 2, 5, 3, 8]

实际返回-101确实有效:

>>> 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'))