Sintaks di belakang diurutkan (key = lambda: ...)

152

Saya tidak begitu mengerti sintaks di balik sorted()argumen:

key=lambda variable: variable[0]

Bukankah lambdasewenang - wenang? Mengapa variabledinyatakan dua kali dalam apa yang tampak seperti dict?

Christopher Markieta
sumber

Jawaban:

162

keyadalah fungsi yang akan dipanggil untuk mengubah item koleksi sebelum mereka dibandingkan. Parameter yang diteruskan ke keyharus berupa sesuatu yang bisa dipanggil.

Penggunaan lambdamenciptakan fungsi anonim (yang dapat dipanggil). Dalam hal sortedcallable hanya membutuhkan satu parameter. Python lambdacukup sederhana. Ia hanya dapat melakukan dan mengembalikan satu hal dengan sungguh-sungguh.

Sintaksnya lambdaadalah kata yang lambdadiikuti oleh daftar nama parameter kemudian satu blok kode. Daftar parameter dan blok kode digambarkan oleh titik dua. Hal ini mirip dengan konstruksi lain di python juga seperti while, for, ifdan sebagainya. Itu semua adalah pernyataan yang biasanya memiliki blok kode. Lambda hanyalah contoh pernyataan dengan blok kode.

Kita dapat membandingkan penggunaan lambda dengan def untuk membuat fungsi.

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

lambda hanya memberi kita cara untuk melakukan ini tanpa menetapkan nama. Yang membuatnya bagus untuk digunakan sebagai parameter untuk suatu fungsi.

variable digunakan dua kali di sini karena di sebelah kiri titik dua itu adalah nama parameter dan di sisi kanan sedang digunakan dalam blok kode untuk menghitung sesuatu.

Evan
sumber
10
note (to OP): harus dihindari untuk menetapkan lambda ke nama (yaitu menggunakannya dengan cara selain sebagai fungsi anonim). jika Anda menemukan diri Anda melakukan ini, Anda mungkin harus menggunakan a def.
wim
151

Saya pikir semua jawaban di sini mencakup inti dari apa fungsi lambda lakukan dalam konteks diurutkan () dengan cukup baik, namun saya masih merasa seperti deskripsi yang mengarah pada pemahaman intuitif yang kurang, jadi inilah dua sen saya.

Demi kelengkapan, saya akan menyatakan yang jelas di depan: sortir () mengembalikan daftar elemen yang diurutkan dan jika kita ingin mengurutkan dengan cara tertentu atau jika kita ingin mengurutkan daftar elemen yang kompleks (misalnya daftar bertingkat atau daftar tupel) kita dapat memanggil argumen kunci.

Bagi saya, pemahaman intuitif dari argumen utama, mengapa harus dipanggil, dan penggunaan lambda sebagai fungsi yang dapat dipanggil (anonim) untuk mencapai hal ini datang dalam dua bagian.

  1. Menggunakan lamba pada akhirnya berarti Anda tidak harus menulis (mendefinisikan) seluruh fungsi, seperti yang dimiliki sblom sebagai contoh. Fungsi Lambda dibuat, digunakan, dan segera dihancurkan - sehingga mereka tidak menggunakan kode Anda dengan lebih banyak kode yang hanya akan digunakan sekali. Ini, seperti yang saya pahami, adalah utilitas inti dari fungsi lambda dan aplikasinya untuk peran tersebut sangat luas. Sintaksnya murni berdasarkan konvensi, yang pada dasarnya adalah sifat sintaksis terprogram secara umum. Pelajari sintaks dan selesaikan dengan itu.

Sintaks Lambda adalah sebagai berikut:

lambda input_variable (s) : enak satu liner

misalnya

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. Gagasan di balik keyargumen adalah bahwa ia harus mengambil dalam set instruksi yang pada dasarnya akan menunjuk fungsi 'diurutkan ()' pada elemen daftar yang harus digunakan untuk mengurutkan berdasarkan. Ketika dikatakan key=, apa artinya sebenarnya: Ketika saya mengulangi daftar elemen satu per satu (yaitu untuk e dalam daftar), saya akan meneruskan elemen saat ini ke fungsi yang saya berikan dalam argumen utama dan menggunakannya untuk membuat daftar yang diubah yang akan memberitahu saya tentang urutan daftar akhir yang disortir.

Saksikan berikut ini:

mylist = [3,6,3,2,4,8,23]
sorted(mylist, key=WhatToSortBy)

Contoh dasar:

sorted(mylist)

[2, 3, 3, 4, 6, 8, 23] # semua angka berurutan dari kecil ke besar.

Contoh 1:

mylist = [3,6,3,2,4,8,23]
sorted(mylist, key=lambda x: x%2==0)

[3, 3, 23, 6, 2, 4, 8] # Apakah hasil yang diurutkan ini masuk akal bagi Anda?

Perhatikan bahwa fungsi lambda saya disortir untuk memeriksa apakah (e) genap atau ganjil sebelum menyortir.

TAPI TUNGGU! Anda mungkin (atau mungkin harus) bertanya-tanya dua hal - pertama, mengapa peluang saya datang sebelum evens saya (karena nilai kunci saya tampaknya memberitahu fungsi saya diurutkan untuk memprioritaskan evens dengan menggunakan operator mod di x%2==0). Kedua, mengapa acara saya rusak? 2 datang sebelum 6 kan? Dengan menganalisis hasil ini, kita akan belajar sesuatu yang lebih dalam tentang bagaimana argumen 'kunci' yang diurutkan () bekerja, terutama dalam hubungannya dengan fungsi lambda anonim.

Pertama, Anda akan melihat bahwa sementara peluang datang sebelum peristiwa, peristiwa itu sendiri tidak diurutkan. Kenapa ini?? Mari kita baca dokumen :

Fungsi Kunci Dimulai dengan Python 2.4, baik list.sort () dan diurutkan () menambahkan parameter kunci untuk menentukan fungsi yang akan dipanggil pada setiap elemen daftar sebelum membuat perbandingan.

Kita harus melakukan sedikit pembacaan di antara baris-baris di sini, tetapi yang dikatakan di sini adalah bahwa fungsi pengurutan hanya dipanggil sekali, dan jika kita menentukan argumen kunci, maka kita mengurutkan berdasarkan nilai yang ditunjuk oleh fungsi kunci.

Jadi apa yang contoh menggunakan pengembalian modulo? Nilai boolean: True == 1, False == 0. Jadi, bagaimana cara menyortir menangani kunci ini? Ini pada dasarnya mengubah daftar asli ke urutan 1 dan 0.

[3,6,3,2,4,8,23] menjadi [0,1,0,1,1,1,0]

Sekarang kita pergi ke suatu tempat. Apa yang Anda dapatkan ketika Anda mengurutkan daftar yang diubah?

[0,0,0,1,1,1,1]

Oke, jadi sekarang kita tahu mengapa peluang muncul sebelum yang jahat. Tetapi pertanyaan selanjutnya adalah: Mengapa 6 masih ada sebelum 2 dalam daftar terakhir saya? Yah itu mudah - ini karena penyortiran hanya terjadi sekali! yaitu 1 itu masih mewakili nilai daftar asli, yang berada di posisi aslinya relatif satu sama lain. Karena penyortiran hanya terjadi satu kali, dan kami tidak memanggil fungsi penyortiran apa pun untuk memesan nilai genap asli dari rendah ke tinggi, nilai-nilai tersebut tetap dalam urutan aslinya relatif terhadap satu sama lain.

Pertanyaan terakhirnya adalah ini: Bagaimana saya berpikir secara konseptual tentang bagaimana urutan nilai boolean saya ditransformasikan kembali ke nilai asli ketika saya mencetak daftar akhir yang diurutkan?

Sorted () adalah metode bawaan yang (fakta menyenangkan) menggunakan algoritma pengurutan hybrid yang disebut Timsortyang menggabungkan aspek semacam penggabungan dan jenis penyisipan. Tampak jelas bagi saya bahwa ketika Anda menyebutnya, ada seorang mekanik yang menyimpan nilai-nilai ini dalam memori dan membundelnya dengan identitas boolean mereka (topeng) yang ditentukan oleh (...!) Fungsi lambda. Urutan ditentukan oleh identitas boolean mereka yang dihitung dari fungsi lambda, tetapi perlu diingat bahwa daftar ini (satu dan nol) tidak sendiri diurutkan berdasarkan nilai aslinya. Oleh karena itu, daftar akhir, sementara diorganisir oleh Odds and Evens, tidak diurutkan berdasarkan sublist (yang dalam hal ini tidak sesuai). Fakta bahwa peluang dipesan adalah karena mereka sudah diurutkan secara kebetulan di daftar asli. Yang bisa diambil dari semua ini adalah bahwa ketika lambda melakukan transformasi itu, urutan asli dari daftar tetap dipertahankan.

Jadi bagaimana semua ini berhubungan kembali dengan pertanyaan awal, dan yang lebih penting, intuisi kita tentang bagaimana kita harus mengimplementasikan sortir () dengan argumen kunci dan lambda?

Fungsi lambda dapat dianggap sebagai pointer yang menunjuk ke nilai-nilai yang perlu kita sortir, apakah itu pointer yang memetakan nilai ke boolean-nya yang ditransformasikan oleh fungsi lambda, atau jika elemen tertentu dalam daftar bersarang, tuple, dikt, dll., sekali lagi ditentukan oleh fungsi lambda.

Mari kita coba dan prediksi apa yang terjadi ketika saya menjalankan kode berikut.

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

sortedPanggilan saya jelas mengatakan, "Tolong urutkan daftar ini". Argumen kunci menjadikannya sedikit lebih spesifik dengan mengatakan, untuk setiap elemen (x) di daftar saya, kembalikan indeks 1 dari elemen itu, lalu urutkan semua elemen dari daftar asli 'daftar saya' dengan urutan daftar yang diurutkan yang dihitung oleh fungsi lambda. Karena kami memiliki daftar tupel, kami dapat mengembalikan elemen yang diindeks dari tupel itu. Jadi kita dapatkan:

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

Jalankan kode itu, dan Anda akan menemukan bahwa ini adalah urutannya. Cobalah mengindeks daftar bilangan bulat dan Anda akan menemukan bahwa kodenya rusak.

Ini adalah penjelasan panjang lebar, tapi saya harap ini membantu untuk 'mengurutkan' intuisi Anda pada penggunaan fungsi lambda sebagai argumen utama dalam diurutkan () dan seterusnya.

PaulG
sumber
8
penjelasan yang sangat baik dan komprehensif. Jawaban ini layak 100 poin. Tapi saya bertanya-tanya mengapa suka kurang untuk jawaban ini.
dicukur
3
Terima kasih atas penjelasannya. Saya membaca dokumen dan menyortir bagaimana-untuk dan tidak jelas bagi saya ide di balik keyfungsi. Jika Anda mencoba memahami sortedfungsi, lambdasintaksisnya baru saja masuk ke cara pemahaman.
sanbor
3
Inilah penjelasan terbaik di sini. Ini sangat berguna dalam membantu saya memahami bagaimana ini sebenarnya bekerja - saya agak memahami fungsi lambda, tetapi menggunakannya dalam konteks sortir () tidak masuk akal. Ini sangat membantu, terima kasih!
TGWaffles
2
Ini jawaban yang cemerlang. Salut tuan
Rajesh Mappu
2
Ini adalah salah satu jawaban favorit saya pada stack overflow. Terima kasih!
AdR
26

lambdaadalah kata kunci Python yang digunakan untuk menghasilkan fungsi anonim .

>>> (lambda x: x+2)(3)
5
Ignacio Vazquez-Abrams
sumber
2
Mengapa ada tanda kurung di sekitar masing-masing?
Christopher Markieta
19
Parens ada di sekitar 3karena sedang diteruskan ke fungsi. Parens berada di sekitar lambda sehingga ekspresi tidak diuraikan sebagai lambda x: x+2(3), yang tidak valid karena 2bukan fungsi.
Ignacio Vazquez-Abrams
Saya tidak yakin saya menyukai fungsi "anonim". Maksud saya, benar bahwa mereka tidak disebutkan, jadi anonim "secara teknis" akurat. Saya lebih suka menyebutnya sebagai "fungsi sementara." Tapi kemudian, saya pedant.
user5179531
12

Bagian variablekiri :adalah nama parameter. Penggunaan variabledi sebelah kanan memanfaatkan parameter.

Berarti hampir persis sama dengan:

def some_method(variable):
  return variable[0]
sblom
sumber
5

Satu lagi contoh fungsi penggunaan diurutkan () dengan key = lambda. Mari kita pertimbangkan Anda memiliki daftar tupel. Di setiap tuple Anda memiliki merek, model, dan berat mobil dan Anda ingin mengurutkan daftar tupel ini berdasarkan merek, model, atau berat. Anda bisa melakukannya dengan 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]))

Hasil:

[('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)]
pengisi36
sumber
3

lambdaadalah fungsi anonim, bukan fungsi sewenang-wenang. Parameter yang diterima akan menjadi variabel yang Anda kerjakan, dan kolom tempat Anda mengurutkannya.

Makoto
sumber
1

Sekadar pengulangan, tombol (Opsional. Fungsi yang dieksekusi untuk memutuskan urutan. Default tidak ada) dalam fungsi yang diurutkan mengharapkan fungsi dan Anda menggunakan lambda.

Untuk mendefinisikan lambda, Anda menentukan properti objek yang ingin Anda urutkan dan fungsi diurutkan built-in python akan secara otomatis mengurusnya.

Jika Anda ingin mengurutkan berdasarkan beberapa properti maka berikan kunci = lambda x: (property1, property2).

Untuk menentukan urutan-oleh, masukkan kebalikan = true sebagai argumen ketiga (Opsional. Boolean. Salah akan mengurutkan naik, Benar akan mengurutkan menurun. Default adalah Salah) dari fungsi yang diurutkan.

kta
sumber
1

Sederhana dan tidak memakan waktu dengan contoh yang relevan dengan pertanyaan yang diajukan. Ikuti contoh ini:

 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"]))

Lihatlah nama-nama dalam daftar, mereka mulai dengan D, B, C dan A. Dan jika Anda perhatikan usia, mereka adalah 55, 44, 33 dan 22. Kode cetak pertama

print(sorted(user, key=lambda el: el["name"]))

Hasil ke:

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

mengurutkan nama, karena dengan key = lambda el: el ["name"] kita menyortir nama dan nama kembali dalam urutan abjad.

Kode cetak kedua

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

Hasil:

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

mengurutkan berdasarkan usia, dan karenanya daftar kembali berdasarkan urutan usia.

Coba kode ini untuk pemahaman yang lebih baik.

AbdullahS96
sumber