web-dev-qa-db-ja.com

ソートの背後にある構文(key = lambda:...)

sorted()引数の背後にある構文はよくわかりません。

key=lambda variable: variable[0]

lambdaは任意ではありませんか? variableのように見えるものにdictが2回記述されているのはなぜですか?

129

keyは、比較される前にコレクションのアイテムを変換するために呼び出される関数です。 keyに渡されるパラメーターは、呼び出し可能なものでなければなりません。

lambdaを使用すると、匿名関数(呼び出し可能)が作成されます。 sortedの場合、呼び出し可能オブジェクトは1つのパラメーターのみを取ります。 Pythonのlambdaは非常に単純です。本当にできることは1つだけです。

lambdaの構文は、Word lambdaの後にパラメーター名のリストが続き、その後にコードの単一ブロックが続きます。パラメータリストとコードブロックはコロンで区切られています。これは、pythonの他の構成体(whileforifなど)と同様です。これらはすべて、通常コードブロックを持つステートメントです。ラムダは、コードブロックを持つステートメントの別のインスタンスです。

関数を作成するために、lambdaの使用とdefの使用を比較できます。

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

lambdaは、名前を割り当てずにこれを行う方法を提供します。関数のパラメーターとして使用するのに最適です。

variableはここで2回使用されます。コロンの左側ではパラメーターの名前であり、右側では何かを計算するためにコードブロックで使用されているためです。

140
Evan

ここでの答えはすべて、sorted()のコンテキストでラムダ関数が行うことの核心を非常にうまくカバーしていると思いますが、直感的な理解につながる説明がまだ不足しているように感じます。

完全を期すために、前もって明確に述べておきます。sort()は、並べ替えられた要素のリストを返します。特定の方法で並べ替えたい場合や、要素の複雑なリスト(ネストされたリストやタプルのリスト)キー引数を呼び出すことができます。

私にとって、重要な引数の直感的な理解、なぜ呼び出し可能にする必要があるのか​​、そしてこれを達成するための(匿名の)呼び出し可能関数としてのラムダの使用は2つの部分に分かれています。

  1. 最終的に、lambaを使用すると、sblomの例のように、関数全体を記述する(定義する)必要がなくなります。 Lambda関数は作成され、使用され、すぐに破棄されます。そのため、一度しか使用されないコードをコードに追加することはありません。これは、私が理解しているように、ラムダ関数の中心的なユーティリティであり、そのような役割への応用は広範です。その構文は純粋に慣例によるものであり、これは本質的にプログラムの構文一般の性質です。構文を学び、それで完了します。

ラムダ構文は次のとおりです。

ラムダinput_variable(s)tasty one liner

例えば.

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=の場合、実際の意味は次のとおりです。一度に1要素ずつリストを反復処理する(つまり、リスト内のe)ために、キー引数で指定した関数に現在の要素を渡して使用します最終的なソート済みリストの順序を通知する変換済みリストを作成します。

見てみな:

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]#このソートされた結果は、直感的に理解できますか?

私のラムダ関数は、ソートの前に(e)が偶数か奇数かをチェックするようにソートに指示していることに注意してください。

ちょっと待って!あなたは2つのことを疑問に思っているかもしれません(最初に、なぜ私のオッズが私の偶数より前に来るのですか(私のキー値はx%2==0のmod演算子を使用してソートされた関数に偶数を優先するように指示しているようだから)第二に、どうして私のイベントは調子が悪いのですか? 2が6の前に来ますか?この結果を分析することで、特に匿名ラムダ関数と組み合わせて、sorted() 'key'引数がどのように機能するかについて、さらに深く学習します。

まず、オッズは偶数よりも前になりますが、偶数自体はソートされません。どうしてこれなの?? ドキュメントを読むことができます

キー関数Python 2.4以降では、list.sort()とsort()の両方が関数を指定するキーパラメーターを追加しました。比較を行う前に、各リスト要素で呼び出されます。

ここで行間を少し読む必要がありますが、これは、ソート関数が1回だけ呼び出され、キー引数を指定した場合、キー関数が指す値でソートすることを示しています。

では、モジュロを使用した例は何を返しますか?ブール値: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は、元のリスト値を表し、それらは相互に元の位置にあります。並べ替えは1回しか行われず、元の偶数の値を低から高に並べ替えるための並べ替え関数を呼び出さないため、これらの値は元の順序のまま残ります。

最後の質問は次のとおりです。最終的なソート済みリストを印刷するときに、ブール値の順序が元の値にどのように変換されるかについて概念的に考えるにはどうすればよいですか?

Sorted()は、(楽しい事実) Timsort と呼ばれるハイブリッドソートアルゴリズムを使用する組み込みメソッドで、マージソートと挿入ソートの側面を組み合わせています。あなたがそれを呼び出すと、これらの値をメモリに保持し、ラムダ関数によって決定されたブールアイデンティティ(マスク)でそれらをバンドルするメカニズムがあることは私には明らかだと思われます(...!)順序は、ラムダ関数から計算されたブールIDによって決定されますが、これらのサブリスト(1と0)は元の値でソートされないことに注意してください。したがって、最終リストは、オッズとイーブンで編成されていますが、サブリストでソートされていません(この場合のイーブンは順不同です)。オッズが順序付けられているという事実は、それらが元のリストで偶然にすでに順序付けられていたためです。これからの重要な点は、lambdaがその変換を行うときに、サブリストの元の順序が保持されることです。

それで、これは元の質問にどのように関連し、さらに重要なことには、キー引数とラムダでsorted()を実装する方法に関する直感ですか?

そのラムダ関数は、ラムダ関数によって変換されたブール値に値をマッピングするポインターか、ネストされたリストの特定の要素であるかどうかにかかわらず、ソートする必要がある値を指すポインターと考えることができますdictなど。これもラムダ関数によって決定されます。

次のコードを実行するとどうなるかを試してみてみましょう。

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

sorted呼び出しは明らかに、「このリストをソートしてください」と言っています。キー引数は、mylistの各要素(x)に対して、その要素のインデックス 1 を返し、元のリスト「mylist」のすべての要素をラムダ関数によって計算されたリストのソート順。タプルのリストがあるため、そのタプルからインデックス付き要素を返すことができます。だから我々は得る:

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

そのコードを実行すると、これが順序であることがわかります。整数のリストにインデックスを付けてみると、コードが壊れていることがわかります。

これは長い説明でしたが、sorted()およびそれ以降の主要な引数としてラムダ関数を使用するという直感を「ソート」するのに役立つことを願っています。

104
PaulG

lambdaはPythonキーワードで、 匿名関数の生成 に使用されます。

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

:の左のvariableはパラメーター名です。右側のvariableの使用は、パラメーターを使用しています。

ほぼ同じ意味:

def some_method(variable):
  return variable[0]
12
sblom

lambdaは、任意の関数ではなく、匿名関数です。受け入れられるパラメーターは、作業中の変数と、それを並べ替える列です。

3
Makoto

sorted()のコンテキストでラムダの使用が求められたので、これも見てください https://wiki.python.org/moin/HowTo/Sorting/#Key_Functions

2
Kristof Pal