sorted(key = lambda:…)后面的语法


Answers:


162

key是一个函数,在比较集合的项目之前将调用该函数。传递给的参数key必须是可调用的。

使用lambda创建一个匿名函数(可调用)。在sorted可调用的情况下仅采用一个参数。Python lambda很简单。它只能做并真正返回一件事。

语法lambda是单词,lambda后跟参数名称列表,然后是单个代码块。参数列表和代码块用冒号表示。这类似于在python其他构建体,以及诸如whileforif等。它们都是通常具有代码块的语句。Lambda只是带有代码块的语句的另一个实例。

我们可以将lambda与def的使用进行比较,以创建一个函数。

adder_lambda = lambda parameter1,parameter2: parameter1+parameter2
def adder_regular(parameter1, parameter2): return parameter1+parameter2

lambda只是为我们提供了一种无需分配名称的方法。这非常适合用作函数的参数。

variable 在此使用两次,因为在冒号的左手边它是参数的名称,而在右手边它在代码块中用于计算某些内容。


10
注意(给OP):应避免为名称分配lambda(即,以非匿名函数的方式使用它)。如果您发现自己在执行此操作,则可能应该使用def
2012年

151

我认为这里的所有答案都很好地涵盖了lambda函数在sorted()上下文中的作用的核心,但是我仍然感觉缺乏对直观理解的描述,所以这里是我的两分钱。

为了完整起见,我先说一下显而易见的事情:sorted()返回已排序元素的列表,以及是否要以特定方式排序或是否要对元素的复杂列表进行排序(例如,嵌套列表或元组列表),我们可以调用key参数。

对我来说,关键参数的直观理解,为什么它必须是可调用的以及使用lambda作为(匿名)可调用函数来完成此操作的过程分为两个部分。

  1. 最终,使用lamba意味着您不必编写(定义)整个函数,就像一个例子所提供的那样。Lambda函数可以被创建,使用和立即销毁-因此它们不会使您的代码与只会被使用一次的更多代码捆绑在一起。据我了解,这是lambda函数的核心实用程序,它在此类角色中的应用广泛。它的语法纯属约定,从本质上讲,这通常是程序语法的本质。学习语法并完成它。

Lambda语法如下:

lambda input_variable(s)好吃的一班轮

例如

In [1]: f00 = lambda x: x/2

In [2]: f00(10)
Out[2]: 5.0

In [3]: (lambda x: x/2)(10)
Out[3]: 5.0

In [4]: (lambda x, y: x / y)(10, 2)
Out[4]: 5.0

In [5]: (lambda: 'amazing lambda')() # func with no args!
Out[5]: 'amazing lambda'
  1. key参数背后的想法是,它应该接受一组指令,这些指令本质上将把“ sorted()”功能指向那些应该用于排序的列表元素。当它说时key=,它的真正含义是:当我一次遍历列表中的一个元素时(即对于列表中的e),我将把当前元素传递给我在key参数中提供的函数,并使用该元素。创建一个转换后的列表,该列表将通知我最终排序列表的顺序。

看看这个:

mylist = [3,6,3,2,4,8,23]
sorted(mylist, key=WhatToSortBy)

基本示例:

sorted(mylist)

[2、3、3、4、6、8、23]#所有数字按从小到大的顺序排列。

范例1:

mylist = [3,6,3,2,4,8,23]
sorted(mylist, key=lambda x: x%2==0)

[3,3,23,6,2,4,8]#此排序结果对您来说是否直观?

请注意,我的lambda函数告诉sorted在排序之前检查(e)是偶数还是奇数。

可是等等!您可能(或者也许应该)想知道两件事-首先,为什么我的赔率比我的赔率还要高(因为我的关键值似乎是在告诉我的排序函数通过使用中的mod运算符来优先考虑偶数x%2==0)。第二,为什么我的偶数不正常?2先于6吧?通过分析此结果,我们将更深入地了解sorted()'key'参数如何工作,尤其是与匿名lambda函数结合使用时。

首先,您会注意到虽然赔率先于偶数,但偶数本身并未排序。为什么是这样??让我们阅读文档

关键函数从Python 2.4开始,list.sort()和sorted()都添加了一个关键参数,以指定要在进行比较之前在每个列表元素上调用的函数。

我们必须在这里在各行之间进行一些阅读,但这告诉我们,sort函数仅被调用一次,并且如果我们指定key参数,那么我们将按key函数指向我们的值进行排序。

那么使用模数返回的示例又是什么呢?布尔值:True == 1False == 0。那么排序如何处理这个键?它基本上将原始列表转换为1和0的序列。

[3,6,3,2,4,8,23]变为[0,1,0,1,1,1,0]

现在我们到了某个地方。对转换后的列表进行排序会得到什么?

[0,0,0,1,1,1,1]

好的,现在我们知道了为什么赔率要高于平均赔率了。但是,下一个问题是:为什么最终列表中的6仍然排在2之前?嗯,这很容易-因为排序只发生一次!即那些1仍然代表原始列表值,它们处于彼此相对的原始位置。由于排序仅发生一次,并且我们不调用任何排序函数来将原始偶数值从低到高排序,因此这些值相对于彼此保持原始顺序。

那么最后的问题是:当我打印出最终的排序列表时,我如何在概念上思考布尔值的顺序如何转换回原始值?

Sorted()是一种内置方法(事实)使用称为Timsort的混合排序算法结合了合并排序和插入排序的各个方面。在我看来,当您调用它时,有一种机制可以将这些值保存在内存中,并将它们与由(...!)lambda函数确定的布尔标识(掩码)捆绑在一起。顺序由通过lambda函数计算出的布尔身份确定,但请记住,这些子列表(一个和一个零)本身并不按其原始值排序。因此,最终列表虽然由奇数和偶数组织,但不会按子列表排序(在这种情况下,偶数是乱序的)。赔率排序的事实是因为它们在原始列表中已经是巧合的。从所有这些中得出的结论是,当lambda进行该转换时,将保留子列表的原始顺序。

那么,这一切与原始问题有何关系,更重要的是,我们对如何使用关键参数和lambda实现sorted()的直觉?

该lambda函数可以被视为指向我们需要排序的值的指针,它是将值映射到由lambda函数转换后的布尔值的指针,还是其在嵌套列表tuple中的特定元素, dict等,同样由lambda函数确定。

让我们尝试预测当我运行以下代码时会发生什么。

mylist = [(3, 5, 8), (6, 2, 8), ( 2, 9, 4), (6, 8, 5)]
sorted(mylist, key=lambda x: x[1])

我的sorted电话显然说:“请对该列表进行排序”。关键参数通过对mylist中的每个元素(x)说,返回该元素的索引1,然后按lambda函数。由于我们有一个元组列表,因此我们可以从该元组返回一个索引元素。这样我们得到:

[(6,2,8),(3,5,8),(6,8,5),(2,9,4)]

运行该代码,您会发现这就是命令。尝试索引整数列表,您会发现代码中断。

这是一个冗长的解释,但是我希望这有助于“整理”您对使用lambda函数作为sorted()及以后的关键参数的直觉。


8
出色而全面的解释。这个答案应得100分。但我想知道为什么不喜欢这个答案。
贾韦德

3
感谢您的深入解释。我阅读了文档并排序了操作方法,但我不清楚该key函数背后的想法。如果您试图理解sorted函数,那么它们的lambda语法就会进入理解的方式。
桑博'17

3
这是最好的解释。这对帮助我了解它的实际工作方式非常有用-我对lambda函数进行了掌握,但在sorted()上下文中使用它毫无意义。这真的很有帮助,谢谢!
TGWaffles

2
这是一个绝妙的答案。先生,向您问好。
拉耶什·马普普

2
这是我最喜欢的堆栈溢出答案之一。谢谢!
AdR

26

lambda是一个Python关键字,用于生成匿名函数

>>> (lambda x: x+2)(3)
5

2
为什么每个括号周围都有括号?
Christopher Markieta 2012年

19
括号周围,3因为它被传递给函数。括号位于lambda周围,因此表达式不会被解析为lambda x: x+2(3),这是无效的,因为2它不是函数。
伊格纳西奥·巴斯克斯

我不确定我是否喜欢术语“匿名”功能。我的意思是,确实没有给他们命名,所以匿名在技术上是准确的。我宁愿将它们称为“临时功能”。但是,那时我是一个学徒。
user5179531

12

variable左侧:是参数名称。采用variable右侧正在使用的参数。

意思几乎完全相同:

def some_method(variable):
  return variable[0]

5

使用key = lambda的sorted()函数的另一个示例。让我们考虑一下您有一个元组列表。在每个元组中,您都有汽车的品牌,型号和重量,并且您想要按品牌,型号或重量对这个元组列表进行排序。您可以使用lambda来完成。

cars = [('citroen', 'xsara', 1100), ('lincoln', 'navigator', 2000), ('bmw', 'x5', 1700)]

print(sorted(cars, key=lambda car: car[0]))
print(sorted(cars, key=lambda car: car[1]))
print(sorted(cars, key=lambda car: car[2]))

结果:

[('bmw', 'x5', '1700'), ('citroen', 'xsara', 1100), ('lincoln', 'navigator', 2000)]
[('lincoln', 'navigator', 2000), ('bmw', 'x5', '1700'), ('citroen', 'xsara', 1100)]
[('citroen', 'xsara', 1100), ('bmw', 'x5', 1700), ('lincoln', 'navigator', 2000)]

3

lambda是匿名函数,不是任意函数。接受的参数将是您正在使用的变量以及对其进行排序的列。



1

换个说法,排序函数中的键(可选。要执行以决定顺序的函数。默认为None)需要一个函数,而您使用的是lambda。

要定义lambda,请指定要排序的对象属性,而python的内置排序函数将自动处理它。

如果要按多个属性排序,则分配key = lambda x:(property1,property2)。

要指定排序方式,请将sorted函数的第三个参数(可选。布尔值。False将按升序排序,True将按降序排序。默认值为False)传递reverse = true。


1

简单且不耗时的答案,并提供与所提问题相关的示例,请 按照以下示例操作:

 user = [{"name": "Dough", "age": 55}, 
            {"name": "Ben", "age": 44}, 
            {"name": "Citrus", "age": 33},
            {"name": "Abdullah", "age":22},
            ]
    print(sorted(user, key=lambda el: el["name"]))
    print(sorted(user, key= lambda y: y["age"]))

查看列表中的名称,它们以D,B,C和A开头。如果您注意到年龄,则分别是55、44、33和22。第一个打印代码

print(sorted(user, key=lambda el: el["name"]))

结果为:

[{'name': 'Abdullah', 'age': 22}, 
{'name': 'Ben', 'age': 44}, 
{'name': 'Citrus', 'age': 33}, 
{'name': 'Dough', 'age': 55}]

对名称进行排序,因为通过key = lambda el:el [“ name”]我们对名称进行排序,并且名称按字母顺序返回。

第二次印刷代码

print(sorted(user, key= lambda y: y["age"]))

结果:

[{'name': 'Abdullah', 'age': 22},
 {'name': 'Citrus', 'age': 33},
 {'name': 'Ben', 'age': 44}, 
 {'name': 'Dough', 'age': 55}]

按年龄排序,因此列表按年龄升序返回。

尝试使用此代码可以更好地理解。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.