Python'da golf oynamak için hangi genel ipuçlarınız var? Kod-golf problemlerine uygulanabilecek ve en azından Python'a özgü olan fikirler arıyorum (örneğin, "yorumları kaldır" bir cevap değildir).
Lütfen cevap başına bir ipucu gönderin.
Python'da golf oynamak için hangi genel ipuçlarınız var? Kod-golf problemlerine uygulanabilecek ve en azından Python'a özgü olan fikirler arıyorum (örneğin, "yorumları kaldır" bir cevap değildir).
Lütfen cevap başına bir ipucu gönderin.
Yanıtlar:
Yerine a=b=c=0kullanın a,b,c=0,0,0.
Yerine a,b,c='123'kullanın a,b,c='1','2','3'.
Şartlı maddeler uzun olabilir. Bazı durumlarda, basit bir koşullu ile değiştirebilirsiniz (a,b)[condition]. Eğer conditiondoğruysa, o bzaman iade edilir.
Karşılaştırmak
if a<b:return a
else:return b
Buna
return(b,a)[a<b]
a if a<b else bvea<b and a or b
(lambda(): b, lambda(): a)[a < b]()lambdas ile kendi kısa devrenizi yapın
P and A or Bveren A'yı düşünün bool(A)=False. Ama (P and [A] or [B])[0]işi yapacak. Referans için diveintopython.net/power_of_introspection/and_or.html adresine bakın .
Bir zamanlar yaptığım harika bir şey:
if 3 > a > 1 < b < 5: foo()
onun yerine:
if a > 1 and b > 1 and 3 > a and 5 > b: foo()
Python'un karşılaştırma operatörleri rock.
Python 2'de her şeyin karşılaştırılabilir olduğunu kullanarak, andoperatörü bu şekilde önleyebilirsiniz . Örneğin, eğer a, b, cve dtam sayılardır,
if a<b and c>d:foo()
bir karakterle kısaltılabilir:
if a<b<[]>c>d:foo()
Bu, her listenin herhangi bir tam sayıdan daha büyük olduğunu kullanır.
Eğer cve dlisteler ise, bu daha da iyi olur:
if a<b<c>d:foo()
3>a>1<b<5
[$a => $b]->[$b <= $a]:)
if(a<b)+(c>d):foo()
*. Bir orolur+
foo()if 3>a>1<b<5
Yerleşik bir işlevi tekrar tekrar kullanıyorsanız, farklı argümanlar kullanıyorsanız, yeni bir ad vermek daha az yer kaplar:
r=range
for x in r(10):
for y in r(100):print x,y
Bazen Python kodunuz 2 girinti seviyesine sahip olmanızı gerektirir. Yapılacak belirgin şey, her girinti seviyesi için bir ve iki boşluk kullanmaktır.
Ancak, Python 2, sekme ve boşluk karakterlerini farklı girinti seviyeleri olarak kabul eder.
Bu, ilk girinti seviyesinin bir boşluk, ikincisi bir sekme karakteri olabileceği anlamına gelir.
Örneğin:
if 1:
if 1:
\tpass
\tSekme karakteri nerede .
TabError: inconsistent use of tabs and spaces in indentation.
Dize değiştirme kullanın ve bu execgibi uzun anahtar kelimelerle baş etmek lambdaiçin kodunuzda sık sık tekrarlayın.
a=lambda b:lambda c:lambda d:lambda e:lambda f:0 # 48 bytes (plain)
exec"a=`b:`c:`d:`e:`f:0".replace('`','lambda ') # 47 bytes (replace)
exec"a=%sb:%sc:%sd:%se:%sf:0"%(('lambda ',)*5) # 46 bytes (%)
Hedef dize çok sık 'lambda ', 7 bayt uzunluğunda. Kod pasajınızın noluşumlarını içerdiğini 'lambda 've sbayt uzunluğunda olduğunu varsayalım . Sonra:
plainseçenektirs bayt uzunluğunda.replaceseçenektirs - 6n + 29 bayt uzunluğunda.%Seçenektirs - 5n + 22 + len(str(n)) bayt uzunluğunda.Kaydedilmiş bir bayt arsadanplain bu üç seçenek için, bunu görebilirsiniz:
exec"..."%(('lambda ',)*5) 2 bayt kazandırır ve en iyi seçenektir.exec"...".replace('`','lambda ')sizin en iyi seçenektir.Diğer durumlar için aşağıdaki tabloyu indeksleyebilirsiniz:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 (occurences)
+---------------------------------------------------------
3 | - - - - - - - - - - - - - - r r r r r
4 | - - - - - - - - - r r r r r r r r r r
5 | - - - - - - - r r r r r r r r r r r r
6 | - - - - - r r r r r r r r r r r r r r
7 | - - - - % r r r r r r r r r r r r r r
8 | - - - % % r r r r r r r r r r r r r r
9 | - - - % % r r r r r r r r r r r r r r
10 | - - % % % r r r r r r r r r r r r r r
11 | - - % % % r r r r r r r r r r r r r r
12 | - - % % % r r r r r r r r r r r r r r r = replace
13 | - - % % % r r r r r r r r r r r r r r % = string %
14 | - % % % % r r r r r r r r r r r r r r - = do nothing
15 | - % % % % r r r r r r r r r r r r r r
(length)
Örneğin, dize lambda x,y:(uzunluk 11) kodunuzda 3 kez meydana gelirse, yazmamanız daha iyi olur exec"..."%(('lambda x,y:',)*3).
replaceçok büyük.
=>bu sadece bir dizedir = lambda . Örneğin, f=>:0olurdu f = lambda: 0.
Birçok dilden bir dize seçmek için genişletilmiş dilimleme kullanın
>>> for x in 0,1,2:print"fbboaaorz"[x::3]
...
foo
bar
baz
vs
>>> for x in 0,1,2:print["foo","bar","baz"][x]
...
foo
bar
baz
Bu iki Boolean durumda, bir de yazabilirsiniz
b*"string"or"other_string"
için
["other_string","string"][b]
Birleştirmeden farklı olarak, bu, herhangi bir uzunlukta dizeler için işe yarar, ancak bbunun yerine bir ifade ise operatör öncelikli sorunlara sahip olabilir .
for x in ("foo","bar","baz"): print x
x. Golf sahası "fbboaaorz"[x::3]vs vs ["foo","bar","baz"][x]Nasıl xdeğer elde edilir golf çözümünüzün başka bir parçası olacaktır.
`n`Bir tamsayıyı kullanmak yerine bir dizgeye dönüştürmek için kullanın str(n):
>>> n=123
>>> `n`
'123'
İlk on iki ingilizce numarasının hangisinde olduğu gibi bir Boolean arama tablosunu kodlamak istediğinizi varsayalım n.
0: False
1: True
2: False
3: False
4: False
5: False
6: False
7: True
8: False
9: True
10:True
11:True
12:False
Ardından, bu arama tablosunu tam olarak aşağıdaki gibi uygulayabilirsiniz:
3714>>i&1
ile sonuçlanan 0veya 1ona eşit Falseolmak True.
Fikri sihirli sayısı Bit dizisi olarak tablo depolar olmasıdır bin(3714)= 0b111010000010ile, nkarşılık gelen (sonundan) inci basamak ninci tablosu girdisi. Biz erişmek nsayı bitshifting tarafından inci girişi nsağa boşluklar ve son rakam alınıp &1.
Bu depolama yöntemi çok etkilidir. Alternatiflerle karşılaştır
n in[1,7,9,10,11]
'0111010000010'[n]>'0'
Arama tablonuzun ayıklanabilecek çok bitli girişleri saklamasını sağlayabilirsiniz.
340954054>>4*n&15
ilgili dört bitlik bloğu çıkartmak için.
Diyelim ki bir m*nızgaranın hücreleri üzerinde yineleniyorsunuz . İki iç içe fordöngü yerine , biri satır için ve sütunlardan biri için m*n, ızgara hücreleri üzerinde yineleme yapmak için tek bir döngü kullanmak genellikle daha kısadır . Döngünün içindeki hücrenin satırını ve sütununu çıkarabilirsiniz.
Orijinal kod:
for i in range(m):
for j in range(n):
do_stuff(i,j)
Golf kodu:
for k in range(m*n):
do_stuff(k/n,k%n)
Sonuç olarak, size çiftini kodlayan iki aralıkları Kartezyen ürün üzerinde yineleme ediyoruz (i,j)olarak x=i*n+j. Pahalı bir rangearama ve döngü içinde bir girinti düzeyi kurtardınız . Yineleme sırası değişmez.
Kullanım //yerine /sen başvurursanız Python 3'te ive jbirçok kez, onların değerlerini atamak için hızlı olabilir i=k/n, j=k%ndöngü içinde.
for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
ndöngüler: repl.it/EHwa
itertools.productözellikle kartezyen ürünler üretirken, iç içe geçmiş halkalardan çok daha özlü olabilir. a1, a2, b1, b2kartezyen çarpım örnekleridir 'ab've'12'
Aşağıdaki simge eveya ile başlamazsa E. Bir sayının ardından boşluğu kaldırabilirsiniz.
Örneğin:
if i==4 and j==4:
pass
Oluyor:
if i==4and j==4:
pass
Bunu karmaşık bir satır ifadesinde kullanmak epeyce karakter kazandırabilir.
EDIT: @ marcog'un belirttiği gibi 4or a, çalışacak, ancak a or4değişken bir isimle karıştırıldığı için çalışmayacaktır.
if(i,j)==(4,4):daha kısa ve bu özel durumda dahaif i==j==4:
4or açalışır, ancak değila or4
0orAyrıca çalışmıyor ( 0osekizlik sayılar için bir ön ek).
0 or xdaima geri dönecek x. Belki de kesebilir 0 or.
0ordaha uzun bir sayının parçası olarak iyi. 10 or xeşittir 10or x.
Tamsayı niçin yazabilirsiniz
n+1 gibi -~nn-1 gibi ~-n çünkü bit çevirme ~xeşittir -1-x. Bu, aynı sayıda karakteri kullanır, ancak operatör önceliği için dolaylı olarak boşlukları veya pareleri kesebilir.
Karşılaştırmak:
while n-1: #Same as while n!=1
while~-n:
c/(n-1)
c/~-n
or f(n)+1
or-~f(n)
(n-1)/10+(n-1)%10
~-n/10+~-n%10
Operatörler ~ve tekli -daha yüksek önceliğe *, /, %ikili sistemin aksine, +.
-~-xtek baytlık ve kaydeder (1-x).
a+b+1daha kısa bir şekilde olduğu gibi yazılabilmesidir a-~b.
n-i-1sadece n+~i.
Yinelemeli bir listeyi Python 3'te listelemek için güzel bir yol :
hayal edebileceğin bir şey olduğunu hayal et
i = (1,2,3,4)
i = range(4)
i = (x**2 for x in range(5))
Fakat bir listeye ihtiyacınız var:
x=list(i) #the default way
*x,=i #using starred assignment -> 4 char fewer
Bir dizgeden bir karakter listesi yapmak çok yararlıdır.
s=['a','b','c','d','e']
s=list('abcde')
*s,='abcde'
*s,='abcde've sonra sbenim interaktif python3 bir segfault ile çöküyor :(
[*'abcde'].
Bunun yerine range(x), gerçekte aşağıdakileri kullanmanız *gerekmiyorsa, işleci herhangi bir şeyin listesinde kullanabilirsiniz i:
for i in[1]*8:pass
aksine
for i in range(8):pass
Bunu iki defadan fazla yapmanız gerekirse, bir değişkene yinelenebilir herhangi bir şey atayabilir ve bu değişkeni istediğiniz aralık ile çarpabilirsiniz:
r=1,
for i in r*8:pass
for i in r*1000:pass
Not : Bu genellikle daha uzun exec"pass;"*8, bu hile sadece bir seçenek olmadığı zaman kullanılmalıdır.
[1]*8kısa olduğundan range(8), bir yerden tasarruf edersiniz, çünkü for i in[...yasal olmadığı için yasaldır for i in range..." dır.
exec"pass;"*8önemli ölçüde daha kısa.
r=1, r*88 ise ve bir sayı ile yinelenemezsiniz. Sanırım demek r=[1]
Sıraları tersine çevirmek için eski güzel gülen yüzünü kullanabilirsiniz:
[1, 2, 3, 4][::-1] # => [4, 3, 2, 1]
Bunu açıklamanın en iyi yolu bir örnek:
>>> a,*b,c=range(5)
>>> a
0
>>> b
[1, 2, 3]
>>> c
4
Bunun için bir kullanım gördük - yinelemeyi Python 3'te bir listeye dönüştürmek :
a=list(range(10))
*a,=range(10)
İşte birkaç kullanım daha.
a=L[-1]
*_,a=L
Bazı durumlarda, bu aynı zamanda ebeveynlerden tasarruf sağlayan ilk öğeyi almak için de kullanılabilir:
a=(L+[1])[0]
a,*_=L+[1]
a=1;b=2;c=[]
a,b,*c=1,2
_,*L=L
*L,_=L
Bunlar alternatiflerden daha kısa L=L[1:]ve L.pop(). Sonuç farklı bir listeye de kaydedilebilir.
@Grc'nin izniyle
a=1;L=[]defa yazdım . Karakterleri bu kadar basit bir şeye kaydedebilmeniz şaşırtıcı.
a,*L=1,), ama yine de bir char kaydeder :)
a,*_,b=L
Bu gibi kümeler yazabilirsiniz. S={1,2,3}Bu, üyeliği kontrol etmek {e}&Syerine, e in Sbir karakterden tasarruf edebileceğiniz anlamına da gelir .
ifboşluk if{e}&S:
not intarafından {e}-So hile ile
Yıllar boyunca, tüm alfabeyi elde etmek için kısa bir yol düşünememesi beni rahatsız etti. Eğer kullanırsanız rangeyeterli olduğunu R=range, ardından programda olan değerdir
[chr(i+97)for i in R(26)]
naiften daha kısa
'abcdefghijklmnopqrstuvwxyz'
, ancak aksi takdirde, tek bir karakterle daha uzun. Bazı ascii değerleri bilgisini gerektiren zekice olanın, sadece tüm harfleri yazmaktan daha ayrıntılı olduğu sonucuna vardım.
Kızımın Alfabesi için bu cevabı görene kadar . Bu dahinin OP'nin işi olup olmadığını ya da bir yorum yapan tarafından bir öneri olup olmadığını anlamak için düzenleme geçmişini yeterince takip edemiyorum, ancak bu 26 harften oluşan bir yineleme oluşturmanın en kısa yoludur (inanıyorum). Roma alfabesinde.
map(chr,range(97,123))
Eğer durum önemli değilse, büyük harf kullanarak başka bir karakteri çıkarabilirsiniz:
map(chr,range(65,91))
Kullandığım mapyolu çok fazla, ben bu hiç aklıma gelmedi bilmiyorum.
string.lowercase- bunun için orada.
ord('z')) yerine 256 ? Aynı uzunlukta olması dışında ... Ayrıca, alfanümerik maddelere ihtiyacınız varsa, str.isalpha@ quintopia versiyonunu ile değiştirin str.isalnum. (Ancak yalnızca bir davaya ihtiyacınız olursa, tüm 36 karakterli dize bundan daha uzun değildir filter(str.isalnum,map(chr,range(90))).)
R, '%c'*26%tuple(R(97,123))range
Python'un anahtar ifadeleri olmamasına rağmen, bunları sözlüklerle taklit edebilirsiniz. Örneğin, böyle bir geçiş yapmak istiyorsanız:
switch (a):
case 1:
runThisCode()
break
case 2:
runThisOtherCode()
break
case 3:
runThisOtherOtherCode()
break
ifİfadeleri kullanabilir veya bunu kullanabilirsiniz:
exec{1:"runThisCode()",2:"runThisOtherCode()",3:"runThisOtherOtherCode()"}[a]
veya bu:
{1:runThisCode,2:runThisOtherCode,3:runThisOtherOtherCode}[a]()
tüm kod yolları aynı parametrelerle çalışıyorsa bu daha iyidir.
Varsayılan bir değeri desteklemek için şunu yapın:
exec{1:"runThisCode()"}.get(a,"defaultCode()")
(veya bu:)
{1:runThisCode}.get(a,defaultCode)()
Bunun bir başka avantajı da fazlalıklarınız varsa, bunları sözlüğün bitiminden sonra ekleyebilmenizdir:
exec{'key1':'code','key2':'code'}[key]+';codeThatWillAlwaysExecute'
Ve sadece bir değeri döndürmek için bir anahtar kullanmak istiyorsanız:
def getValue(key):
if key=='blah':return 1
if key=='foo':return 2
if key=='bar':return 3
return 4
Bunu sadece yapabilirsin:
getValue=lambda key:{'blah':1,'foo':2,'bar',3}.get(key,4)
dict(s1=v1,s2=v2,...,sn=vn)yerine {'s1':v1,'s2':v2,...,'sn':vn}2 * n-4 bayt kaydeder ve n> = 3
İki boolean değerlere sahip, zaman ave bhem olmadığını öğrenmek istiyorsanız, ave bdoğru kullanmak *yerine and:
if a and b: #7 chars
vs
if a*b: #3 chars
Değerlerden herhangi biri yanlışsa, bu ifadedeki gibi değerlendirilir 0ve bir tamsayı değeri yalnızca sıfır değilse doğrudur.
&: a=b=False,a&b
+için orsize garanti edemez eğera != -b
|her durumda çalışır.
*bunun yerine and/ &&birçok baytta bazı baytları kaydeder.
Python 2, bir nesneyi yalnızca 2 karakter pahasına xdize olarak temsil etmenize olanak sağlar `x`. Bunu, nesnenin dizesinde nesnenin kendisinden daha kolay yapılan işler için kullanın.
Karakterleri birleştir
Karakterlerin bir listesini Verilen l=['a','b','c']bir üretebilir ''.join(l)olarak `l`[2::5]bir bayt kazandırır.
Bunun nedeni ise `l`bir "['a', 'b', 'c']"tane ikinci sıfır endeksli karakter olduğunu başlayarak liste dilim harfleri ayıklamak, böylece (boşluklu) ave oradan her beşinci karakter alarak. Bu, çok karakterli dizelere katılmak veya benzeri şekilde gösterilen karakterlerden kaçmak için çalışmaz '\n'.
Rakamları birleştir
Benzer şekilde, boş olmayan bir basamak listesi göz önüne alındığında l=[0,3,5], bunlardan biri dize '035'olarak birleştirilebilir `l`[1::3].
Bu gibi bir şey yaparak kaydeder map(str,l). Tek basamaklı olmaları gerektiğini ve birbirine 1.0karıştırılmış gibi kayan noktalara sahip olamayacaklarına dikkat edin . Ayrıca, bu boş listede hata veriyor ].
Negatifleri kontrol et
Şimdi, string olmayan bir görev için. lGerçek sayıların bir listeniz olduğunu ve herhangi bir negatif sayı içerip içermediğini test etmek istediğinizi varsayalım .
Yapabilirsin
'-'in`l`
hangi dize rep bir negatif işareti arar. Bu ikisinden de kısa
any(x<0for x in l)
min(l+[0])<0
İkincisi, min(l)<0boş listede başarısız olur, bu yüzden riskten korunmanız gerekir.
str(l)[2::5]12 bayt, 19'a karşılık ''.join(map(str,l)). Bunun ortaya çıktığı asıl durum ( lbir jeneratör ifadesi, liste değil) beni sadece bir bayt kurtardı ... ki buna hala değer!
Lambda ile tek satırlık bir fonksiyon yapılabilir:
def c(a):
if a < 3: return a+10
else: return a-5
dönüştürülebilir (eksik alanı not edin 3andve 10or)
c=lambda a:a<3and a+10or a-5
c=lambda a:a+[-5,10][a<3]. ve / veya püf noktası, kısa devre davranışına bağlı olduğunuzda daha kullanışlıdır
else: durdurarak düşürülebilir return, böylece izleyen her şey sadece ifkoşul başarısız olursa, aka elsekoşul doğruysa gerçekleştirilir. Böylece elsegüvenle atlanabilir. (Oradaki
c=lambda a:a-5+15*(a<3)
Herhangi bir bölünme için yuvarlama sonucu elde etmek istiyorsanız, //taban için yaptığınız gibi , math.ceil(3/2)15 veya -(-3//2)8 bayt için daha kısa kullanabilirsiniz .
math.floor(n) : 13 bytes+12 for import
n//1 : 4 bytes
math.ceil(n) : 12 bytes+12 for import
-(-n//1) : 8 bytes
n//1+1
round(x)bir (x+.5)//1+ 1 bayt ancak ile ikinci başlar, (ve eğer xsabit oluşan bir toplamı olan yararlı olabilir.
+=kullanın appendveextendA.append(B)
kısaltılabilir:
A+=B,
B,Burada uzatmak için kullanılabilecek bir tek eleman tuple oluşturur Agibi [B]içinde A+=[B].
A.extend(B)
kısaltılabilir:
A+=B
return 0ya return 1eşdeğerdir return Falseya return True.
-xyerine x*-1. --8.32yerine -8.32*-1. Ya da sadece 8.32...
A+=B Bbir olduğunu tuple.
Bir koşula göre iki sayılardan birini seçme
Sen zaten biliyor listeleri seçim kullanmak için [x,y][b]bir BooleANDile büçlü ifadesi için y if b else x. Değişkenler x, yve bayrıca, ifadeler olabilir nota rağmen her iki xvey hatta değerlendirilir seçili değilken.
İşte rakam xve ne zaman bazı potansiyel optimizasyonlar y.
[0,y][b] -> y*b [1,y][b] -> y**b [x,1][b] -> b or x[x,x+1][b] -> x+b[x,x-1][b] -> x-b[1,-1][b] -> 1|-b[x,~x][b] -> x^-b[x,y][b] -> x+z*b(veya y-z*b), burada z = yx.Ayrıca değiştirebilir xve bunun yerine olumsuzlama olarak yyeniden yazabilirsiniz b.
Python 3.5'in piyasaya sürülmesiyle listelerin, tuplelerin, setlerin ve diktelerin manipülasyonu daha da golfe çıktı.
Çiftleri karşılaştırın:
set(T)
{*T}
list(T)
[*T]
tuple(T)
(*T,)
Çok daha kısa! Bununla birlikte, bir şeyi bir listeye dönüştürmek ve bir değişkene atamak istiyorsanız, normal uzatılmış yinelemeli paket açma işleminin daha kısa olduğunu unutmayın:
L=[*T]
*L,=T
Benzer bir sözdizimi tuples için işe yarar:
T=*L,
hangi genişletilmiş tekrarlanabilir açılabilir, ancak diğer tarafta yıldız ve virgül ile.
Her iki tarafa da bir liste / grup eklemeniz gerekirse, ambalajın açılması birleştirme işleminden biraz daha kısadır:
[1]+T+[2]
[1,*T,2]
(1,)+T+(2,)
(1,*T,2)
Bu bununla sınırlı değil print, ama kesinlikle kilometrenin çoğunun geleceği yer. PEP448 şimdi olduğu gibi çoklu paket açmaya izin veriyor:
>>> T = (1, 2, 3)
>>> L = [4, 5, 6]
>>> print(*T,*L)
1 2 3 4 5 6
Bu muhtemelen çok sık gerçekleşmeyecektir, ancak sözdizimi en az üç öğe güncelliyorsanız sözlükleri güncellemekten tasarruf etmek için kullanılabilir:
d[0]=1;d[1]=3;d[2]=5
d={**d,0:1,1:3,2:5}
Bu temelde herhangi bir ihtiyacı ortadan kaldırmaktadır dict.update.
>>> for i in range(x):s+=input()
Eğer i değeri işe yaramazsa:
>>> for i in[0]*x:s+=input()
veya
>>> exec's+=input();'*x
for i in[0]*x:s+=input()Başka bir yerden tasarruf etmek için ikinci örneği yapabilirsiniz . Ayrıca, exec ve almak için ilk tırnak işareti arasındaki boşluğu kaldırabilirsinizexec's+=input();'*x
for i in[0]*x:s+=input()