Lambda'da atama için Python geçici çözümleri


34

Bu Python'da golf oynamak için bir ipucu.

Python golfünde, bir sunumun lambda olarak tanımlanan bir fonksiyon olması yaygındır. Örneğin,

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

x'in faktörünü hesaplar .

Lambda formatının iki büyük avantajı vardır :

  • Bir klişe f=lambda x:...veya lambda x:...daha kısadır def f(x):...return...yax=input()...print...
  • Özyinelemeli bir çağrı, küçük bayt ek yükü ile döngü oluşturmak için kullanılabilir.

Ancak, lambdalar sadece tek bir ifadeye izin vermenin büyük bir dezavantajına sahiptir; Özellikle, bu hiçbir atama anlamına gelir c=chr(x+65). Bu, değerinin iki kez (veya daha fazla) referans alınması gereken uzun bir ifadeye sahip olduğunda sorunludur.

Gibi atamalar E=enumerate, işlev dışında veya isteğe bağlı bir argüman olarak mümkündür, ancak işlev girişlerine bağlı olmadıklarında mümkündür. Tanımlama zamanında değerlendirildiğinde f=lambda n,k=min(n,0):...girdi ntanımlanmadığı için başarısız gibi isteğe bağlı argümanlar k.

Sonuç olarak, bazen bir lambdada uzun bir ifadeyi tekrarlamayı emersiniz, çünkü alternatif uzun bir lambda değildir.

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

Kesim noktası, a veya geçiş yaptığınız yerden yaklaşık 11 karakterdir ( ayrıntılar ) . Bunu, yinelenen bir ifade için normal uzunluktaki 5 eşitlik noktası 5 ile karşılaştırın:defprogram

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

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

Diğer dillerin geçici çözümleri var, örneğin Octave . Python için bilinen püf noktaları vardır, ancak bunlar uzun, tıknaz ve / veya sınırlı kullanım içindir. Bir lambdada atamayı simüle etmenin kısa, genel amaçlı bir yöntem Python golfünde devrim yaratacaktır.


Bir Python golfçüsünün bu sınırlamanın üstesinden gelmek ya da bunun üstesinden gelmek için yolları nelerdir? Bir lambdada iki kez tekrarlanan uzun bir ifade gördüklerinde akıllarında ne gibi fikirler olmalı?

Bu ipuçlarını soruyla amacım bu soruna derinlemesine dalmak ve:

  • Bir lambda içinde sahte atama yapmak için golf geçici çözümlerini kataloglayın ve analiz edin
  • Daha iyi yöntemler için yeni müşteri adayları keşfedin

Her cevap bir geçici çözümü veya potansiyel bir ipucunu açıklamalıdır.


Bunun Python'da iyi yapılamayan şeylerden biri olduğunu tahmin ediyorum. JavaScript bu konuda bir ayağı var.
mbomb007

Orlp'ın cevabında olduğu gibi, Neil'in iç içe lambdaları kullanma konusundaki önerisi, yine de iç içe lambdaya ihtiyaç duyduğunuz durumlarda def'den daha uzun değildir. Ben daha ayrıntılı analiz hak ediyor bence.
Martin Ender

2
Tersine çevrilen küçük harfli dize bitiştirme ile verilen kesin örnek için bir tane başvurabilir lambda s:(s+s[::-1]).lower(). Tabii bu asıl soruya cevap vermiyor.
Jonathan Allan,

@JonathanAllan İyi nokta, olarak değiştirildi strip.
xnor

Yanıtlar:


6

eval

Bu kendi içinde o kadar da iyi değil, ancak çözümünüz zaten evalbir şekilde veya formda kullanıyorsa, genellikle bu tekniği kullanabilirsiniz.

eval("%f*%f+%f"%((5**.5,)*3))

Vay, bu akıllı! Neden böyle bir kod görmüyorum?
z0rberg

6
@ z0rberg Muhtemelen eval'ün kötü olduğu için.
HyperNeutrino,

Bu kodlamaya abone olmuyorum. #EvalLivesMatter ... ama cidden, bu basit dll enjeksiyonundan nasıl daha kötü?
z0rberg

6

Python 3.8'da atama ifadeleri

Python 3.8 ( TIO ), atama ifadelerini sunar. ,:= bir parçası olarak değişken bir satır içi atamak için kullanılan atama ifadelerini sunar.

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

Bu bir içinde kullanılabilir lambda atamalara normal olarak izin verilmediği yerde . Karşılaştırmak:

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

Daha fazlası için bu ipucuna bakın .


2

İç lambda

Bunlar aynı anda birden fazla değişken tanımlamanıza izin verir.

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

vs.

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

çok daha uzun, ancak birden fazla değişkeniniz veya daha uzun olan ve birçok kez tekrarlanan değişkenleriniz varsa:

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

Karakter sayımı

İlk: (lambda:)()(11 bayt)
İlk değişken: [space]a(2 bayt)
Sonraki değişkenler: ,b,(3 bayt)
Kullanım: a(1 bayt).

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

(Ayrıca parantezlerde tasarruf sağlar)

Yani, bu 3n + 10baytları alır n, değişkenlerin sayısı nerede . Bu yüksek bir başlangıç ​​maliyetidir, ancak sonunda ödeme yapabilir. Hatta içsel değerini de döndürür, böylece birden fazla iç içe geçebilirsiniz (Bu hızla buna değmeyecek olsa da).

Bu, def f():a=...;b=...;returngenellikle yalnızca kısa olacak şekilde yuvalanmış liste kavramalarındaki uzun ara hesaplamalar için kullanışlıdır .

1 değer için, bu tasarruf sağlar:, bu uses * length - length - uses - 13yüzden yalnızca bu ifade pozitif olduğunda kullanışlıdır.
Bir İçin nkullanılan farklı ifadeler ubunların birleşik uzunluğu toplam zamanları l, bu kaydeder:
l - (3 * n) - u - 10 ( + brackets removed )


1

Bir liste kullanın

Parametre olarak bir listesini bildirmek ve kullanımı .append() ordeğeri saklamak için:
lambda s:s.lower()+s.lower()[::-1]
döner olarak
lambda s,l=[]:l.append(s.lower())or l[-1]+l[-1][::-1]

Karakter sayımı:

,l=[]5 karakter
l.append()or13 karakter
l[-1]her kullanım için 5 karakter

Başa baş

Eklenen karakter miktarı:
uses*(5-length) + 18 + length
Bir önceki örnekte ifade s.lower()9 karakter uzunluğunda ve 2 kez kullanılmış, bu tekniği uygulayarak 19 karakter ekledi. 7 kez kullanılsaydı, 1 karakterlik bir azalma olur.
Bu tekniğe gereken asgari kullanım miktarı
min_uses = (18+length)/(length-5)

Upsides

  • Az bir ücret karşılığında yeni bir atamaya izin ver (liste zaten açıklandı)
  • Bir mı listnesne yüzden [0], .pop(), [x:y]ve diğer liste fonksiyonları hileler için kullanılabilir. durumsal durum

Downsides

  • Yüksek ilk maliyet
  • Yüksek kullanım maliyeti
  • Sadece uzunluğu daha büyük olan kullanımlar için çalışır. 5

Sözlük kullan

teşekkürler @Zgarb
yukarıdaki Declare ile aynı fikre parametresi ve kullanımı gibi bir sözlük .setdefault()deposunda (ve dönüş) değerine:
lambda s:s.lower()+s.lower()[::-1]
içine döner
lambda s,d={}:d.setdefault(0,s.lower())+d[0][::-1]
aksine, o Not listmeslektaşı setdefaultatanan değer döndürür.

Karakter sayımı:

,d={}5 karakter
d.setdefault(k,)16 karakter
d[k]her kullanım için 4 karakter

Başa baş

Eklenen karakterin miktarı:
(uses-1)*(4-length) + 21
Bir önceki örnekte, ifade s.lower()9 karakter uzunluğundadır ve 2 kez kullanılmıştır, bu tekniği uygulayarak 16 karakter eklemiştir. 7 kez kullanılsaydı, 1 karakterlik bir azalma olur.
Bu tekniğe gereken asgari kullanım miktarı
min_uses = 1-21/(4-length)

Upsides / Downsides

  • Temelde listeyle aynı
  • Sadece uzunluğu daha büyük olan kullanımlar için çalışır. 4

Diğer hususlar

  • Bu teknik karakter azaltmaya değerse, lambdamuhtemelen düşürülebilir ve işlev daha kısa bir program için def/ ile yeniden yazılabilir input.
  • As @FlipTack işaret, liste ve dict keept OLAN bu, bu özyinelemeli çağrılar çoğunlukla Rahatsız kullanılabilir olurken, işlev çağrılar arasında. yine yüksek durumsal
  • Sözlük her zaman listeden daha kısa olacaktır.

3
İşlev gönderimleri bir kereden fazla kullanılabilir olmak zorunda. Şu anda bu lambda her çalıştırıldığında aynı listeyi kullanmaktadır, bu da daha sonraki çalışmalarda işleri tersine çevirebilir.
FlipTack

@FlipTack'in ilgisini çekti, meta gibi bir kaynağı bağlar mısın? Bu kuralın bildiğim birkaç püf noktası üzerinde bir etkisi olabileceğini düşünüyorum.
JAD


Bir sözlükle daha iyisini yapabileceğini düşünüyorum: lambda s,d={}:d.setdefault(0,s.lower())+d[0][::-1]Aynı zamanda yeniden kullanılabilir.
Zgarb

Aynı list.extendanda birden çok öğe eklemek için kullanabilirsiniz ; bu, list.appendbirden çok kez kullanmaktan daha kısa olacaktır .
mbomb007

0

Değişkenleri ayarlamak ve işlemden sonraki gibi verileri döndürmek için kullanın:

add = lambda x, y: exec("x+=y")

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

0

Kavrama listesi

Bu çok çirkin, çünkü son çare, ama yapabilirsiniz
[<expression> for <variable> in <value>]
bir lambda bir değişken sözde ayarlamak için . Temel olarak, bu yöntemle ilgili tek iyi nokta, içsel ifadenin okunabilir kalabilmesidir, ki bu golf oynarken endişenizin en az olduğu açıktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.