191

我不太明白sorted()参数背后的语法:

key=lambda variable: variable[0]

不是lambda随意的吗?为什么variable在看起来像 a 中两次声明dict

4

10 回答 10

208

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

为了完整起见,我先声明一下: sorted() 返回已排序元素的列表,如果我们想以特定方式排序,或者如果我们想对复杂的元素列表(例如嵌套列表或元组列表)我们可以调用 key 参数。

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

  1. 使用 lamba 最终意味着您不必编写(定义)整个函数,就像sblom提供的示例一样。Lambda 函数被创建、使用并立即销毁——因此它们不会用更多只会使用一次的代码来混淆您的代码。据我了解,这是 lambda 函数的核心实用程序,它对这种角色的应用是广泛的。它的语法纯粹是一种约定,本质上是一般程序语法的本质。学习语法并完成它。

Lambda 语法如下:

lambda input_variable(s): tasty one liner

lambdapython关键字在哪里。

例如

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=时,它的真正含义是:当我遍历列表时,一次一个元素(即for e in some_list),我将把当前元素传递给 key 参数指定的函数并使用它来创建一个转换list 将通知我最终排序列表的顺序。

看看这个:

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是偶数还是奇数。

可是等等!您可能(或应该)想知道两件事。

首先,为什么奇数出现在偶数之前?毕竟,键值似乎是通过使用in 运算符告诉sorted函数优先考虑偶数。modx % 2 == 0

二、为什么偶数还是乱序?2 在 6 之前,对吧?

通过分析这个结果,我们将更深入地了解“key”参数是如何工作的,尤其是与匿名 lambda 函数结合使用时。

首先,您会注意到虽然赔率出现在偶数之前,但偶数本身并没有排序。为什么是这样??让我们阅读文档

关键函数从 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 函数转换的布尔值的指针,还是它是嵌套列表、元组中的特定元素, 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电话显然说:“请对这个列表进行排序”。关键参数通过说,'对于 中的每个元素,返回该元素的第二个索引,然后按照 lambda 函数计算的列表的排序顺序对原始列表的所有元素进行排序,从而使其x更加具体mylistmylist由于我们有一个元组列表,我们可以使用 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() 中的关键参数,以及其他。

于 2017-03-23T03:03:40.867 回答
205

key是一个函数,将被调用以在比较集合的项目之前对其进行转换。传递给的参数key必须是可调用的。

的使用lambda创建了一个匿名函数(它是可调用的)。sorted在可调用的情况下,只需要一个参数。Python的lambda很简单。它真的只能做和回报一件事。

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

我们可以比较使用 lambda 和 def 来创建一个函数。

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

lambda 只是为我们提供了一种无需指定名称即可执行此操作的方法。这使得它非常适合用作函数的参数。

variable在这里使用了两次,因为在冒号的左边它是一个参数的名称,而在右边它在代码块中用于计算某些东西。

于 2012-01-23T02:26:36.613 回答
30

lambda是用于生成匿名函数的 Python 关键字。

>>> (lambda x: x+2)(3)
5
于 2012-01-23T02:11:35.427 回答
13

variable左边:是参数名称。右边的使用variable是利用参数。

意思几乎完全一样:

def some_method(variable):
  return variable[0]
于 2012-01-23T02:11:49.657 回答
9

另一个使用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)]
于 2019-09-12T13:32:32.537 回答
3

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

于 2012-01-23T02:11:50.163 回答
3

简单且不费时的答案,提供与所问问题相关的示例 遵循此示例:

 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}]

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

试试这个代码以获得更好的理解。

于 2020-02-06T09:00:21.957 回答
3

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降序排列),然后在同一个子组中,根据每个实例的第二个元素进行排序实例的(按升序排列,因为它是默认选项)。

希望这对您有一些有用的信息!

于 2021-01-31T05:44:03.860 回答
2

由于在上下文中询问了 lambda 的用法,因此也请sorted()查看此https://wiki.python.org/moin/HowTo/Sorting/#Key_Functions

于 2013-10-25T13:03:48.600 回答
1

换句话说,排序函数中的键(可选。执行以确定顺序的函数。默认为无)需要一个函数,并且您使用 lambda。

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

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

要指定 order-by,请将 reverse= true 作为 sorted 函数的第三个参数(可选。布尔值。False 将升序排序,True 将降序排序。默认为 False)。

于 2019-09-13T03:39:49.507 回答