如何在Python中使用lambda表达式进行排序

338
我正在尝试根据属性对一些值进行排序,如下所示:
a = sorted(a, lambda x: x.modified, reverse=True)

我收到了如下错误信息:

<lambda>() takes exactly 1 argument (2 given)

为什么?我该如何修复它?


这个问题最初是针对Python 2.x编写的。在3.x中,错误消息将会不同:TypeError:sorted期望1个参数,但得到了2个


12
添加关键字参数 key=lambda x: x.modified 将解决这个问题。 - shahjapan
5个回答

529

使用

a = sorted(a, key=lambda x: x.modified, reverse=True)
#             ^^^^

在Python 2.x版本中,sorted函数按照以下顺序接受参数:
sorted(iterable, cmp=None, key=None, reverse=False)

如果没有key=,则传入的函数将被视为一个接受两个参数的cmp函数。


24
通过这次经历,你有很好的机会学习欣赏关键字参数传递的优点。 - Tony Veijalainen
1
这很古老,但是你有任何想法为什么错误代码会误导?你的回答听起来像是可能Python正在向lambda提供另一个参数,因为cmp函数需要2个参数? - SuperBiasedMan
1
@SuperBiasedMan 错误并不具有误导性。cmp,一个比较函数需要两个参数。如果您没有指定传递一个 key,则假定从函数参数顺序中传递了一个比较器。您的 lambda 只接受一个参数,因此不是有效的比较器,这就是错误信息所说的内容。 - Jezor
2
Python 2和3似乎有不同的函数声明。我使用Python 3,所以没有cmp了。在Python 2中,它是一个“iterable”,那么在Python 3中是什么呢? - Timo

75
lst = [('candy','30','100'), ('apple','10','200'), ('baby','20','300')]
lst.sort(key=lambda x:x[1])
print(lst)

它将会打印如下:

[('apple', '10', '200'), ('baby', '20', '300'), ('candy', '30', '100')]

1
这对于字符串整数无效。看看这个!lst = [('999','9'),('303','30'),('343','34')] lst.sort(key = lambda x:x [1]) print(lst) - Daniel Kua
1
结果是[('303','30'),('343','34'),('999','9')],这不是按每个列表中第二个元素排序的。 - Daniel Kua
1
lst = [('糖果','999','9'), ('苹果','303','30'), ('宝贝','343','34')] lst.sort(key=lambda x:x[2]) print(lst) - Daniel Kua
1
[('apple', '303', '30'), ('baby', '343', '34'), ('candy', '999', '9')]。这个列表没有按照第二个元素排序! - Daniel Kua
6
很容易修复。你只需要将 x[1] 改为 int(x[1]) 就可以了。 - M-Chen-3
这个答案对我很有帮助。谢谢! - lam vu Nguyen

12

您正在尝试使用lambda函数进行键函数操作。

Python和其他语言(如C#或F#)使用lambda函数

此外,就关键函数而言,根据文档

list.sort()sorted()都有一个key参数, 用于在进行比较之前指定要对每个列表元素调用的函数。

...

key参数的值应为一个函数,该函数接受单个参数并返回用于排序目的的键。此技术非常快,因为关键字函数仅针对每个输入记录调用一次。

因此,关键函数具有键参数,并且确实可以接收lambda函数。

Real Python中有一个很好的示例。假设您有以下列表:

ids = ['id1', 'id100', 'id2', 'id22', 'id3', 'id30']

并且想要对其“整数”进行排序。然后,您可以执行以下操作:

sorted_ids = sorted(ids, key=lambda x: int(x[2:])) # Integer sort

并且打印它将会给出

['id1', 'id2', 'id3', 'id22', 'id30', 'id100']
在您的情况下,您只需要在lambda前面写上key=。因此,您应该使用以下内容。
a = sorted(a, key=lambda x: x.modified, reverse=True)

8

看看这个示例,您就会明白:

示例1:

a = input()
a = sorted(a, key = lambda x:(len(x),x))
print(a)

输入: ["tim", "bob", "anna", "steve", "john","aaaa"]
输出: ['bob', 'tim', 'aaaa', 'anna', 'john', 'steve']

输入: ["tim", "bob", "anna", "steve", "john","aaaaa"]
输出: ['bob', 'tim', 'anna', 'john', 'aaaaa', 'steve']


例子 2 (高级):

a = ["tim", "bob", "anna", "steve", "john","aaaaa","zzza"]
a = sorted(a, key = lambda x:(x[-1],len(x),x))
print(a)

输出: ['anna', 'zzza', 'aaaaa', 'bob', 'steve', 'tim', 'john']


示例3(高级):

a = [[1,4],[2,5],[3,1],[1,6],[3,8],[4,9],[0,3],[2,6],[9,5]]
a = sorted(a, key = lambda x:(-x[1],x[0]))
print(a)

输出:[[4, 9], [3, 8], [1, 6], [2, 6], [2, 5], [9, 5], [1, 4], [0, 3], [3, 1]]


结论:

key = lambda x:(p1,p2,p3,p4,...,pn)
x 是从输入流中逐个读取的元素。
p1,p2,p3...pn 基于这些属性对元素进行排序。
根据 p1>p2>p3>...>pn 的优先顺序进行排序。
我们也可以在排序条件后添加 reverse=True,以按相反顺序排序元素。


8

在Python3中:

    from functools import cmp_to_key
    def compare(i1,i2):
      return i1-i2
    events.sort(key=cmp_to_key(compare))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接