sorted(key=lambda: ...) 后面的语法
Posted
技术标签:
【中文标题】sorted(key=lambda: ...) 后面的语法【英文标题】:Syntax behind sorted(key=lambda: ...) 【发布时间】:2012-02-16 12:02:32 【问题描述】:我不太明白sorted()
参数背后的语法:
key=lambda variable: variable[0]
lambda
不是任意的吗?为什么variable
在看起来像dict
的地方出现两次?
【问题讨论】:
【参考方案1】:我认为这里的所有答案都很好地涵盖了 lambda 函数在 sorted() 上下文中的作用的核心,但是我仍然觉得缺乏导致直观理解的描述,所以这是我的两个美分。
为了完整起见,我先声明一下: sorted() 返回一个已排序元素的列表,如果我们想要以特定方式排序,或者我们想要对一个复杂的元素列表进行排序(例如嵌套列表或元组列表)我们可以调用 key 参数。
对我来说,对 key 参数的直观理解,为什么它必须是可调用的,以及使用 lambda 作为(匿名)可调用函数来实现这一点分为两部分。
-
使用lamba 最终意味着您不必编写(定义)整个函数,就像sblom 提供的示例那样。 Lambda 函数被创建、使用并立即销毁——因此它们不会用更多只会使用一次的代码来混淆您的代码。据我了解,这是 lambda 函数的核心实用程序,它对这种角色的应用是广泛的。它的语法纯粹是一种约定,本质上是一般程序语法的本质。学习语法并完成它。
Lambda 语法如下:
lambda input_variable(s): tasty one liner
lambda
是一个 python 关键字。
例如
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'
key
参数背后的想法是,它应该接受一组指令,这些指令基本上将“sorted()”函数指向那些应该用于排序的列表元素。当它说key=
时,它的真正含义是:当我遍历列表时,一次一个元素(即for e in some_list
),我将把当前元素传递给key 参数指定的函数,然后使用它来创建一个转换后的列表,它将通知我最终排序列表的顺序。
检查一下:
In [6]: mylist = [3, 6, 3, 2, 4, 8, 23] # an example list
# sorted(mylist, key=HowToSort) # what we will be doing
基础示例:
# mylist = [3, 6, 3, 2, 4, 8, 23]
In [7]: sorted(mylist)
Out[7]: [2, 3, 3, 4, 6, 8, 23]
# all numbers are in ascending order (i.e.from low to high).
示例 1:
# mylist = [3, 6, 3, 2, 4, 8, 23]
In [8]: sorted(mylist, key=lambda x: x % 2 == 0)
# Quick Tip: The % operator returns the *remainder* of a division
# operation. So the key lambda function here is saying "return True
# if x divided by 2 leaves a remainer of 0, else False". This is a
# typical way to check if a number is even or odd.
Out[8]: [3, 3, 23, 6, 2, 4, 8]
# Does this sorted result make intuitive sense to you?
请注意,我的 lambda 函数告诉 sorted
在排序之前检查每个元素 e
是偶数还是奇数。
等等!您可能(或应该)想知道两件事。
首先,为什么奇数出现在偶数之前?毕竟,键值似乎是在告诉sorted
函数通过在x % 2 == 0
中使用mod
运算符来确定偶数的优先级。
第二,为什么偶数还是乱序? 2 在 6 之前,对吧?
通过分析这个结果,我们将更深入地了解“key”参数的实际工作原理,尤其是与匿名 lambda 函数结合使用时。
首先,您会注意到虽然赔率出现在偶数之前,但偶数本身并没有排序。为什么是这样?? Lets read the docs:
关键函数 从 Python 2.4 开始,list.sort() 和 sorted() 都添加了一个关键参数来指定要调用的函数 进行比较之前的每个列表元素。
这里我们必须在字里行间做一点阅读,但这告诉我们 sort 函数只被调用一次,如果我们指定 key 参数,那么我们按照 key 函数指向的值排序我们去。
那么使用模数的示例返回什么?一个布尔值:True == 1
、False == 0
。那么 sorted 是如何处理这个键的呢?它基本上将原始列表转换为 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 函数计算的布尔标识确定,但请记住,这些子列表(1 和 0)本身并不是按其原始值排序的。因此,最终列表虽然由 Odds 和 Evens 组织,但不按子列表排序(在这种情况下,偶数是无序的)。赔率排序的事实是因为它们在原始列表中已经巧合了。从这一切中得出的结论是,当 lambda 进行该转换时,子列表的原始顺序将被保留。
那么这一切与最初的问题有什么关系,更重要的是,我们应该如何使用其关键参数和 lambda 实现 sorted() 的直觉?
这个 lambda 函数可以被认为是一个指向我们需要排序的值的指针,无论它是一个将值映射到由 lambda 函数转换的布尔值的指针,还是它是嵌套列表中的特定元素, tuple, dict 等,再次由 lambda 函数确定。
让我们尝试预测当我运行以下代码时会发生什么。
In [9]: mylist = [(3, 5, 8), (6, 2, 8), (2, 9, 4), (6, 8, 5)]
In[10]: sorted(mylist, key=lambda x: x[1])
我的sorted
电话显然说:“请对这个列表进行排序”。关键参数通过说'对于mylist
中的每个元素x
,返回该元素的第二个索引,然后按排序顺序对原始列表mylist
的所有元素进行排序由 lambda 函数计算的列表。由于我们有一个元组列表,我们可以使用 lambda 函数从该元组返回一个索引元素。
将用于排序的指针是:
[5, 2, 9, 8] # the second element of each tuple
排序这个指针列表返回:
[2, 5, 8, 9]
将此应用于mylist
,我们得到:
Out[10]: [(6, 2, 8), (3, 5, 8), (6, 8, 5), (2, 9, 4)]
# Notice the sorted pointer list is the same as the second index of each tuple in this final list
运行该代码,您会发现这是顺序。尝试使用此键函数对整数列表进行排序,您会发现代码中断(为什么?因为您当然不能索引整数)。
这是一个冗长的解释,但我希望这有助于 sort
您对使用 lambda
函数的直觉 - 作为 sorted() 中的关键参数,以及更多。
【讨论】:
优秀而全面的解释。这个答案值得100分。但我想知道为什么喜欢这个答案的人少。 感谢您的深入解释。我read the docs 并整理了操作方法,我不清楚key
函数背后的想法。如果你想理解sorted
函数,他们lambda
语法只是进入理解的方式。
这是最好的解释。这对于帮助我理解它的实际工作方式非常有用——我有点掌握了 lambda 函数,但是在 sorted() 的上下文中使用它没有任何意义。这真的很有帮助,谢谢!
这是一个绝妙的答案。向您致敬,先生。
这是我最喜欢的关于堆栈溢出的答案之一。谢谢!【参考方案2】:
key
是一个函数,将调用该函数以在比较集合项之前对其进行转换。传递给key
的参数必须是可调用的。
lambda
的使用创建了一个匿名函数(可调用)。在sorted
的情况下,可调用对象只接受一个参数。 Python 的lambda
非常简单。它真的只能做和回报一件事。
lambda
的语法是单词lambda
,后跟参数名称列表,然后是单个代码块。参数列表和代码块用冒号表示。这类似于 python 中的其他构造,例如while
、for
、if
等。它们都是通常具有代码块的语句。 Lambda 只是带有代码块的语句的另一个实例。
我们可以比较使用 lambda 和 def 来创建一个函数。
adder_lambda = lambda parameter1,parameter2: parameter1+parameter2
def adder_regular(parameter1, parameter2): return parameter1+parameter2
lambda 只是为我们提供了一种无需指定名称即可执行此操作的方法。这使得它非常适合用作函数的参数。
variable
在这里使用了两次,因为在冒号的左侧是参数的名称,而在右侧则是在代码块中用于计算某些内容。
【讨论】:
注意(给 OP):应避免将 lambda 分配给名称(即以匿名函数以外的方式使用它)。如果您发现自己这样做了,您可能应该只使用def
。【参考方案3】:
lambda
是一个 Python 关键字,用于generate anonymous functions。
>>> (lambda x: x+2)(3)
5
【讨论】:
为什么每个都有括号? 括号在3
附近,因为它被传递给一个函数。括号在 lambda 周围,因此表达式不会被解析为 lambda x: x+2(3)
,这是无效的,因为 2
不是函数。
我不确定我是否喜欢“匿名”函数这个术语。我的意思是,他们没有被命名,所以匿名是“技术上”准确的。我宁愿将它们称为“临时函数”。但是,我是一个书呆子。【参考方案4】:
:
左边的variable
是参数名称。右边variable
的使用是对参数的使用。
意思几乎完全一样:
def some_method(variable):
return variable[0]
【讨论】:
【参考方案5】:另一个使用 sorted() 函数与 key=lambda 的示例。假设您有一个元组列表。在每个元组中,您都有汽车的品牌、型号和重量,并且您希望按品牌、型号或重量对这个元组列表进行排序。你可以用 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)]
【讨论】:
【参考方案6】:lambda
是一个匿名函数,而不是任意函数。被接受的参数将是您正在使用的变量,以及您对其进行排序的列。
【讨论】:
【参考方案7】:简单且不费时的答案,并提供与所提问题相关的示例 按照这个例子:
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]
按年龄排序,因此列表按年龄升序返回。
试试这个代码以获得更好的理解。
【讨论】:
【参考方案8】:lambda
和sorted
的另一种用法如下:
给定输入数组:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
该行:people_sort = sorted(people, key = lambda x: (-x[0], x[1]))
将给出一个people_sort
列表为[[7,0],[7,1],[6,1],[5,0],[5,2],[4,4]]
在这种情况下,key=lambda x: (-x[0], x[1])
基本上告诉sorted
首先根据每个实例的第一个元素的值对数组进行排序(在降序按减号建议的顺序),然后在同一个子组中,根据每个实例的第二个元素进行排序(按升序排列,因为它是默认选项)。
希望这对您有一些有用的信息!
【讨论】:
【参考方案9】:由于在 sorted()
的上下文中询问了 lambda 的用法,因此也请看一下 https://wiki.python.org/moin/HowTo/Sorting/#Key_Functions
【讨论】:
【参考方案10】:只是换个说法,排序函数中的键(可选。执行以确定顺序的函数。默认为无)需要一个函数,并且您使用 lambda。
要定义 lambda,您指定要排序的对象属性,python 内置的 sorted 函数会自动处理它。
如果要按多个属性排序,则指定 key = lambda x: (property1, property2)。
要指定 order-by,请将 reverse= true 作为 sorted 函数的第三个参数(可选。布尔值。False 将升序排序,True 将降序排序。默认为 False)。
【讨论】:
以上是关于sorted(key=lambda: ...) 后面的语法的主要内容,如果未能解决你的问题,请参考以下文章
Python sorted函数|sorted([13,1,237,89,100],key=lambda x:len(str(x)))