【问题标题】:Difficulty understanding lambda function in sort难以理解排序中的 lambda 函数
【发布时间】:2013-03-13 21:32:23
【问题描述】:

假设我定义了一个列表列表lol

lol = [['malasia', 0.02, 56.3], ['chile', 0.03, 34.9],
       ['hungria', 0.01, 45.9], ['ahumada', 0.001, 1]]

那么,

lol.sort(lambda x, y: cmp(y[2], x[2]))

按每个子列表的最后一个元素对lol 进行排序...


我只是想了解sort的组成部分:

  • cmp(y,x) 与数字比较并返回 -1(y 小于 x)、0(x 等于 y)或 1(y 大于 x)。

  • lambda 在每个列表的最后一个元素上定义一个函数? 那么 lambda 里面的排序呢?我很困惑——谁能解释一下 lambda 函数的作用?

【问题讨论】:

  • cmp 参数仅支持向后兼容。它已从 Python3 中删除。始终使用 key= 代替。如果您遇到关键功能无法使用的棘手情况,请使用 functools.cmp_to_key helper

标签: python list lambda


【解决方案1】:

那么 lambda 在一个排序中?我迷路了!

基本上,当sort() 需要比较两个元素时,它会调用 lambda 函数并使用其结果来确定两个元素中的哪一个应该先出现。这就是它的全部。

【讨论】:

  • OP 应该注意到这确实是低效的,因为它为每对元素调用一次。请改用key 函数,因为每个元素只调用一次。
  • @DanielRoseman:我不明白你的意思。你能详细说明一下吗?据我了解,关键功能始终是比较两个元素,否则它应该如何确定另一个元素是在自己之前还是在自己之后。顺便说一句,我认为 timsort 使用 key-func 在幕后自动工作,减少了“双重”比较,但我从未真正深入研究过。
  • @DonQuestion key 函数的要点是它在排序本身开始之前为每个元素运行一次,并提供一个可用于比较的简单值。然后,排序实际上是对键值进行排序,而不是对元素本身进行排序。将其与 cmp 进行比较,对于每个必须进行的比较,都必须调用 cmp 函数。
  • @DanielRoseman:所以基本上,iterable 中的每个项目在预运行中都被 key-func 触及,在第二次运行中被比较函数触及? (我稍微看了一下源代码,似乎它基本上是对 Objects/listobject.c 中某个函数的调用,但我无法确定是哪一个。)
【解决方案2】:

这实际上最好使用sortkey 参数来完成,cmp 有点过时了。

例如:

lol.sort(key=lambda x: x[2])

(您也可以使用 x[-1] 来表示列表的最后一个元素)

您正在创建 lambda 并将其传递给 sort 函数。你也可以这样写:

get_third_element = lambda x: x[2]
lol.sort(key=get_third_element)

或者让它更容易理解:

def get_third_element(x):
    return x[2]

lol.sort(key=get_third_element)

没有理由不能将一个函数作为参数传递给另一个函数!

【讨论】:

    【解决方案3】:

    您示例中的 lambda 函数确定哪个项目先出现。

    在“经典”情况下,它只会计算 x-y:如果结果是 negative,则意味着 x is smaller 然后是 y,因此是 before y

    此外,您可以将反向参数传递给排序方法,这将reverse=True 顺序。

    在这种情况下,您的“排序”函数是“lambda-wrapper”中的 cmp 函数。其中,您将 x 的顺序与 y 交换并使用第三个参数,这意味着它以相反的顺序排序(x/y-swap)并通过比较所有第三个参数来实现(x[2])。

    关于你的第二个子弹:

    ...谁能解释一下 lambda 函数的作用?

    如果您问什么是 lambda 函数:它是一个匿名的轻量级内联函数。匿名意味着它没有标识符。 (但您可以指定一个。例如:sqr = lambda x : x**2,您现在可以像使用任何其他函数一样使用它:y = sqr(2)

    Normal function: def name(arg): vs lambda-function: lambda   arg: ret_value
                      ^    ^    ^                          ^   ^  ^       ^
                      a)   b)   c)                         a)  b) c)      d)
    
    • a) 将以下内容标记为普通/lambda 函数的关键字
    • b) 因此,在 lambda 函数“缺失”的情况下的函数名 匿名
    • c) 函数参数:普通函数 -> 括号,lambda 函数 -> 没有
    • d) 返回值 - 在正常功能的情况下省略,因为 必须用 return 显式返回。 (没有明确返回它 提供 None) lambda 隐式返回 在冒号右侧进行评估。

    您使用排序函数的示例是 lambda 函数的典型用例。它们被用作“丢弃”函数,您可以内联而不创建自己的正常函数。

    一个更“pythonic”的变体是这样的:

    from operator import itemgetter
    
    keyfunc = itemgetter(2) # takes the 3rd argument from an itterable
    sorted_list = sorted(lol, key=keyfunc, reverse=True)
    

    【讨论】:

    • lambda 函数与key 参数(不是函数)完全无关。它只是定义了一个通用函数对象,而不将其与变量相关联。您可以在完全独立于排序的上下文中使用它。例如,要打印“hello”,可以使用:(lambda x: print(x))("hi")
    • a) 返回 None 不等于抛出异常。 b) 可以编写与在 python 2.x 和 3.x 中工作的关键参数无关的 lambda 函数,例如。 lambda x,y: x+y c) 目的是证明 lambda 函数可以用于与排序完全无关的目的,并且它绝不被称为“关键函数”。一个特定的 lambda 函数只是作为 key 参数传递。
    • @Asad:顺便说一句:我不明白你的虚假论点:“......关键参数(不是函数)”!但是我们在同一页上,如果您想从函数中概括出来,关键参数必须至少是 callable
    • 我发布的示例专门用于排序。关键是要表明 lambda 函数与排序无关,因此称它为 key 函数是错误的。你已经纠正了,这很好,但我不明白你在争论什么。 “但你也不完全正确”
    【解决方案4】:

    lambda 属于“函数”类型
    所以你的

    lambda x, y : cmp(y[2], x[2])
    

    等于

    def f(x, y):
        return cmp(y[2], x[2])
    

    sort接受一个函数,当它需要比较两个元素时,它会调用那个lambda函数,它会返回cmp(y[2], x[2])的值

    所以这种排序会以这种方式对您的列表进行排序:当它遇到两个元素时,它会获取“三元组”中的最后一个值并比较它们以确定优先级。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-16
      • 1970-01-01
      • 1970-01-01
      • 2012-11-26
      • 1970-01-01
      • 1970-01-01
      • 2016-01-05
      • 1970-01-01
      相关资源
      最近更新 更多