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


回答:


162

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

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

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

lambdaの使用とdefの使用を比較して、関数を作成できます。

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

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

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


10
注記(OPへ):ラムダを名前に割り当てる(つまり、匿名関数以外の方法で使用する)ことは避けてください。自分でこれを行っている場合は、おそらくdef
2012年

151

ここでのすべての回答は、sorted()のコンテキストでラムダ関数が何をするかの中核を非常にうまくカバーしていると思いますが、私はまだ直感的な理解につながる説明が欠けているように感じるので、ここに2つのセントがあります。

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

私にとって、主要な議論、それを呼び出し可能にする必要がある理由、およびこれを実現するための(匿名の)呼び出し可能な関数としてのラムダの使用の直観的な理解は、2つの部分に分かれています。

  1. 最終的にlambaを使用すると、sblomが例を提供したように、関数全体を記述する(定義する)必要がなくなります。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=、それが実際に意味することは、リストを一度に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つのことを疑問に思うかもしれません(またはおそらくそうするべきです)-最初に、私のオッズが偶数の前に来るのはなぜですか(私のキー値は、ソートされた関数に、でmod演算子を使用して優先順位を付けるように指示しているためx%2==0)第二に、なぜ偶数が壊れているのですか?2は6の前に来ますか?この結果を分析することにより、sorted()の 'key'引数が、特に匿名のラムダ関数と連携してどのように機能するかについて、さらに深い知識を得ることができます。

まず、オッズが偶数の前に来る間、偶数自体はソートされないことに気づくでしょう。どうしてこれなの??ドキュメントを読みましょう

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

ここでは、行間を少し読み取る必要がありますが、これは、sort関数が1回だけ呼び出されることを示しています。key引数を指定すると、key関数が指す値で並べ替えられます。

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

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

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

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

そのラムダ関数は、ラムダ関数によって変換されたブール値に値をマッピングするポインターであるか、ネストされたリストの特定の要素であるタプルであるかなど、並べ替えに必要な値を指すポインターと考えることができます。 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()以降の主要な引数としてラムダ関数の使用に関する直感を「ソート」するのに役立つことを願っています。


8
優れた包括的な説明。この回答は100ポイントに値します。しかし、なぜいいねがこの答えよりも少ないのかと思います。
javed

3
深い説明ありがとうございます。私はドキュメント読み、ハウツーを並べ替えましたが、key関数の背後にある考えがわかりませんでした。あなたがsorted関数を理解しようとしているなら、それらはlambda構文が理解の方法に入るだけです。
sanbor 2017

3
これがここでの最良の説明です。これは実際にこれがどのように機能するかを理解するのに非常に役立ちました-私はラムダ関数を少し把握しましたが、sorted()のコンテキストでそれを使用しても意味がありませんでした。これは本当に役に立ちました、ありがとう!
TGWaffles 2017年

2
これは素晴らしい答えです。敬礼します。
Rajesh Mappu

2
これはスタックオーバーフローに関する私のお気に入りの回答の1つです。ありがとうございました!
AdR 2018年

26

lambda無名関数の生成に使用されるPythonキーワードです。

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

2
それぞれに括弧があるのはなぜですか?
クリストファーマルキエタ2012年

19
3関数に渡されているので、括弧は周りにあります。括弧はラムダの周りにあるため、式はとして解析されませんlambda x: x+2(3)。これは2、が関数ではないため無効です。
Ignacio Vazquez-Abrams

「匿名」関数という用語が好きかどうかはわかりません。つまり、名前が付けられていないことは事実なので、匿名は「技術的に」正確です。私はむしろそれらを「一時的な関数」と呼んでいます。しかし、その後、私はペダントです。
user5179531

12

variable左側は:パラメータ名です。の用法variable権には、パラメータを利用しています。

ほぼ同じ意味:

def some_method(variable):
  return variable[0]

5

key = lambda を使用したsorted()関数の使用例のもう1つ。タプルのリストがあるとしましょう。各タプルには、車のブランド、モデル、および重量があり、このタプルのリストをブランド、モデル、または重量でソートしたいとします。あなたはラムダでそれを行うことができます。

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)は関数を想定しているため、ラムダを使用します。

ラムダを定義するには、並べ替えるオブジェクトプロパティを指定します。Pythonの組み込みの並べ替え関数が自動的に処理します。

複数のプロパティで並べ替える場合は、key = lambda x:(property1、property2)を割り当てます。

order-byを指定するには、sorted関数の3番目の引数として、reverse = trueを渡します(オプション。ブール値。Falseは昇順でソートされ、Trueは降順でソートされます。デフォルトはFalseです)。


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"]で名前を並べ替えているため、名前が並べ替えられ、名前はアルファベット順に返されます。

2番目の印刷コード

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

結果:

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

年齢でソートするため、リストは年齢の昇順で返されます。

理解を深めるには、このコードを試してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.