Penanganan masalah python untuk penugasan di lambda

34

Ini adalah pertanyaan kiat untuk bermain golf di Python.

Dalam bermain golf Python, lazimnya pengiriman adalah fungsi yang didefinisikan sebagai lambda. Sebagai contoh,

f=lambda x:0**x or x*f(x-1)

menghitung faktorial x.

Format lambda memiliki dua keuntungan besar :

  • Pelat f=lambda x:...atau lambda x:...lebih pendek dari def f(x):...return...ataux=input()...print...
  • Panggilan rekursif dapat digunakan untuk mengulang dengan overhead byte kecil.

Namun, lambdas memiliki kelemahan besar yaitu hanya mengizinkan satu ekspresi, tanpa pernyataan. Secara khusus, ini berarti tidak ada tugas yang disukai c=chr(x+65). Ini bermasalah ketika seseorang memiliki ekspresi panjang yang nilainya perlu direferensikan dua kali (atau lebih).

Tugas seperti E=enumeratedimungkinkan di luar fungsi atau sebagai argumen opsional, tetapi hanya jika mereka tidak bergantung pada input fungsi. Argumen opsional seperti f=lambda n,k=min(n,0):...gagal karena input nbelum didefinisikan ketika kdievaluasi pada waktu definisi.

Hasilnya adalah bahwa kadang-kadang Anda menyedot pengulangan ekspresi panjang dalam lambda karena alternatifnya adalah non-lambda yang panjang.

lambda s:s.strip()+s.strip()[::-1]
def f(s):t=s.strip();print t+t[::-1]

Titik impas adalah sekitar 11 karakter ( detail ), yang lalu Anda beralih ke a defatau program. Bandingkan ini dengan titik impas panjang biasanya 5 untuk ekspresi berulang:

range(a)+range(b)
r=range;r(a)+r(b)

print s[1:],s[1:]*2
r=s[1:];print r,r*2

Bahasa lain memiliki solusi, Oktaf misalnya . Ada trik yang dikenal untuk Python, tetapi mereka panjang, kikuk, dan / atau penggunaan terbatas. Metode pendek, tujuan umum untuk mensimulasikan tugas dalam lambda akan merevolusi golf Python.


Apa cara bagi pegolf Python untuk mengatasi atau mengatasi keterbatasan ini? Gagasan potensial apa yang harus mereka pikirkan ketika mereka melihat ekspresi panjang diulang dua kali dalam lambda?

Tujuan saya dengan pertanyaan tips ini adalah untuk menyelam jauh ke dalam masalah ini dan:

  • Katalog dan analisis solusi golf untuk tugas palsu di dalam lambda
  • Jelajahi petunjuk baru untuk metode yang lebih baik

Setiap jawaban harus menjelaskan solusi atau petunjuk potensial.

Tidak
sumber
Saya menduga ini adalah salah satu hal yang tidak dapat dilakukan dengan baik dengan Python. JavaScript memiliki kaki yang satu ini.
mbomb007
Sama seperti jawaban orlp, saran Neil (dihapus) untuk menggunakan lambdas bersarang belum tentu lebih dari def dalam kasus-kasus di mana Anda memerlukan lambda bersarang. Saya pikir itu layak untuk analisis yang lebih menyeluruh.
Martin Ender
2
Untuk contoh yang tepat diberikan dengan concatenation string huruf kecil terbalik seseorang bisa saja pergi lambda s:(s+s[::-1]).lower(). Tentu saja ini tidak menjawab pertanyaan yang sebenarnya.
Jonathan Allan
@ JonathanAllan Poin bagus, ubah ke strip.
xnor

Jawaban:

6

eval

Ini tidak terlalu bagus, tetapi jika solusi Anda sudah menggunakan evalbeberapa cara atau bentuk, Anda biasanya dapat menggunakan teknik ini.

eval("%f*%f+%f"%((5**.5,)*3))
orlp
sumber
Wow, itu pintar! Mengapa saya tidak pernah melihat kode seperti ini?
Z0rberg
6
@ z0rberg Mungkin karena eval itu jahat.
HyperNeutrino
Saya tidak berlangganan kode ini. #EvalLivesMatter ... tapi serius, bagaimana itu lebih buruk daripada injeksi dll?
Z0rberg
6

Ekspresi penugasan dalam Python 3.8

Python 3.8 ( TIO ) memperkenalkan ekspresi penugasan , yang digunakan :=untuk menetapkan inline variabel sebagai bagian dari ekspresi.

>>> (n:=2, n+1)
(2, 3)

Ini dapat digunakan di dalam a lambda, di mana tugas biasanya tidak diizinkan. Membandingkan:

lambda s:(t:=s.strip())+t[::-1]
lambda s:s.strip()+s.strip()[::-1]
def f(s):t=s.strip();return t+t[::-1]

Lihat tip ini untuk informasi lebih lanjut.

Tidak
sumber
2

Lambda batin

Ini memungkinkan Anda untuk mendefinisikan banyak variabel sekaligus.

lambda s:s.strip()+s.strip()[::-1]

vs.

lambda s:(lambda t:t+t[::-1])(s.strip())

jauh lebih lama, tetapi jika Anda memiliki beberapa variabel, atau variabel yang lebih panjang, yang diulang berkali-kali:

lambda a,b,c:a.upper()*int(c)+b.lower()*int(c)+a.upper()[::-1]+b.lower()[::-1]+a.upper()*int(c)+a.lower()*int(c)

vs.

lambda a,B,c:(lambda A,b,n:A*n+b*n+A[::-1]+b[::-1]+A*n+b*c)(a.upper(),B.lower(),int(c))

Jumlah karakter

Awal: (lambda:)()(11 byte)
Variabel pertama: [space]a(2 byte)
Variabel berikutnya: ,b,(3 byte)
Gunakan: a(1 byte).

(lambda* a*_,b_:)(*<value a>*_,<value b>_)

(Juga menghemat kurung)

Jadi, ini membutuhkan 3n + 10byte, di mana njumlah variabel. Ini adalah biaya awal yang tinggi, tetapi pada akhirnya dapat membayar. Bahkan mengembalikan nilai batinnya, sehingga Anda dapat membuat sarang berlipat ganda (Meskipun ini dengan cepat akan menjadi tidak layak.)

Ini benar-benar hanya berguna untuk perhitungan menengah panjang dalam pemahaman daftar bersarang, karena def f():a=...;b=...;returnbiasanya akan lebih pendek.

Untuk 1 nilai, ini menghemat:, uses * length - length - uses - 13jadi hanya berguna ketika ekspresi itu positif.
Untuk nekspresi berbeda yang digunakan utotal waktu, di mana panjang gabungannya l, ini menghemat:
l - (3 * n) - u - 10 ( + brackets removed )

Artyer
sumber
1

Gunakan Daftar

Deklarasikan daftar sebagai parameter dan gunakan .append() oruntuk menyimpan nilai:
lambda s:s.lower()+s.lower()[::-1]
berubah menjadi
lambda s,l=[]:l.append(s.lower())or l[-1]+l[-1][::-1]

Jumlah karakter:

,l=[]5 karakter
l.append()or13 karakter
l[-1]5 karakter untuk setiap penggunaan

Seri

Jumlah karakter yang ditambahkan adalah:
uses*(5-length) + 18 + length
Pada contoh sebelumnya, pernyataannya s.lower()adalah 9 karakter dan digunakan 2 kali, menerapkan teknik ini menambahkan 19 karakter. Jika digunakan 7 kali, akan ada pengurangan 1 karakter.
Jumlah kegunaan minimal untuk teknik ini layak adalah
min_uses = (18+length)/(length-5)

Kelemahan

  • Izinkan tugas baru dengan biaya yang sedikit berkurang (daftar sudah dinyatakan)
  • Adalah listobjek sehingga [0], .pop(), [x:y]dan fungsi daftar lainnya dapat digunakan untuk trik. sangat situasional

Kerugian

  • Biaya awal yang tinggi
  • Biaya penggunaan tinggi
  • Hanya berfungsi untuk penggunaan dengan panjang lebih tinggi dari 5

Gunakan kamus

thanks @Zgarb
Ide yang sama seperti di atas. Deklarasikan kamus sebagai parameter dan gunakan .setdefault()untuk menyimpan (dan mengembalikan) nilainya:
lambda s:s.lower()+s.lower()[::-1]
berubah menjadi
lambda s,d={}:d.setdefault(0,s.lower())+d[0][::-1]
Perhatikan bahwa, tidak seperti listlawannya, setdefaultmengembalikan nilai yang diberikan.

Jumlah karakter:

,d={}5 karakter
d.setdefault(k,)16 karakter
d[k]4 karakter untuk setiap penggunaan

Seri

Jumlah karakter yang ditambahkan adalah:
(uses-1)*(4-length) + 21
Pada contoh sebelumnya pernyataannya s.lower()adalah 9 karakter dan digunakan 2 kali, menerapkan teknik ini menambahkan 16 karakter. Jika digunakan 7 kali, akan ada pengurangan 1 karakter.
Jumlah kegunaan minimal untuk teknik ini layak adalah
min_uses = 1-21/(4-length)

Kelebihan / Kelemahan

  • Pada dasarnya sama dengan daftar
  • Hanya berfungsi untuk penggunaan dengan panjang lebih tinggi dari 4

Pertimbangan lainnya

  • Jika teknik ini sepadan dengan pengurangan karakter, maka lambdamungkin bisa dijatuhkan dan fungsinya ditulis ulang dengan def/ inputuntuk program yang lebih pendek.
  • Seperti yang ditunjukkan @FlipTack , daftar dan dict ADALAH KEEPT antara panggilan fungsi, sementara ini sebagian besar akan mengganggu, itu dapat digunakan pada panggilan rekursif. lagi sangat situasional
  • Kamus akan selalu lebih pendek dari daftar.
tongkat
sumber
3
Pengiriman fungsi harus dapat digunakan lebih dari sekali. Saat ini ini menggunakan daftar yang sama setiap kali lambda dijalankan, yang dapat mengacaukan segalanya di kemudian berjalan.
FlipTack
@FlipTack tidak menarik, maukah Anda menautkan sumber seperti meta? Saya pikir aturan itu mungkin berdampak pada beberapa trik yang saya tahu.
JAD
Saya pikir Anda bisa lebih baik dengan kamus: lambda s,d={}:d.setdefault(0,s.lower())+d[0][::-1]Ini juga dapat digunakan kembali.
Zgarb
Anda dapat menggunakan list.extenduntuk menambahkan beberapa elemen sekaligus, yang akan lebih pendek daripada menggunakan list.appendbeberapa kali.
mbomb007
0

Gunakan untuk mengatur variabel dan mengembalikan data setelah operasi seperti:

add = lambda x, y: exec("x+=y")
Dylan Eliot
sumber
sebagai alternatif: {add = lambda x, y: [x.append (x [0] + y), x.reverse (), x.pop ()]}
Dylan Eliot
0

Daftar pemahaman

Ini lebih merupakan pilihan terakhir karena sangat tidak menarik, tetapi Anda bisa melakukan
[<expression> for <variable> in <value>]
pseudo-set variabel dalam lambda. Pada dasarnya satu-satunya poin bagus tentang metode ini adalah bahwa ekspresi batin dapat tetap dapat dibaca, yang jelas menjadi perhatian Anda saat bermain golf.

Khusus ASCII
sumber