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=0
kullanı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 condition
doğruysa, o b
zaman 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 b
vea<b and a or b
(lambda(): b, lambda(): a)[a < b]()
lambdas ile kendi kısa devrenizi yapın
P and A or B
veren 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, and
operatörü bu şekilde önleyebilirsiniz . Örneğin, eğer a
, b
, c
ve d
tam 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 c
ve d
listeler 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 or
olur+
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
\t
Sekme karakteri nerede .
TabError: inconsistent use of tabs and spaces in indentation.
Dize değiştirme kullanın ve bu exec
gibi uzun anahtar kelimelerle baş etmek lambda
iç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 n
oluşumlarını içerdiğini 'lambda '
ve s
bayt uzunluğunda olduğunu varsayalım . Sonra:
plain
seçenektirs
bayt uzunluğunda.replace
seç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=>:0
olurdu 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 b
bunun 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 x
değ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 0
veya 1
ona eşit False
olmak True
.
Fikri sihirli sayısı Bit dizisi olarak tablo depolar olmasıdır bin(3714)
= 0b111010000010
ile, n
karşılık gelen (sonundan) inci basamak n
inci tablosu girdisi. Biz erişmek n
sayı bitshifting tarafından inci girişi n
sağ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 for
dö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 range
arama 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 i
ve j
birçok kez, onların değerlerini atamak için hızlı olabilir i=k/n
, j=k%n
döngü içinde.
for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
n
dö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, b2
kartezyen çarpım örnekleridir 'ab'
ve'12'
Aşağıdaki simge e
veya 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 or4
değ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
0or
Ayrıca çalışmıyor ( 0o
sekizlik sayılar için bir ön ek).
0 or x
daima geri dönecek x
. Belki de kesebilir 0 or
.
0or
daha uzun bir sayının parçası olarak iyi. 10 or x
eşittir 10or x
.
Tamsayı n
için yazabilirsiniz
n+1
gibi -~n
n-1
gibi ~-n
çünkü bit çevirme ~x
eş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, +
.
-~-x
tek baytlık ve kaydeder (1-x)
.
a+b+1
daha kısa bir şekilde olduğu gibi yazılabilmesidir a-~b
.
n-i-1
sadece 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 s
benim 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]*8
kı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*8
8 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}&S
yerine, e in S
bir karakterden tasarruf edebileceğiniz anlamına da gelir .
if
boşluk if{e}&S:
not in
tarafından {e}-S
o 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 range
yeterli 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 map
yolu ç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 a
ve b
hem olmadığını öğrenmek istiyorsanız, a
ve b
doğ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 0
ve bir tamsayı değeri yalnızca sıfır değilse doğrudur.
&
: a=b=False
,a&b
+
için or
size 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 x
dize 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) a
ve 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.0
karış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. l
Gerç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)<0
boş 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 ( l
bir 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 3and
ve 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 if
koşul başarısız olursa, aka else
koşul doğruysa gerçekleştirilir. Böylece else
gü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 x
sabit oluşan bir toplamı olan yararlı olabilir.
+=
kullanın append
veextend
A.append(B)
kısaltılabilir:
A+=B,
B,
Burada uzatmak için kullanılabilecek bir tek eleman tuple oluşturur A
gibi [B]
içinde A+=[B]
.
A.extend(B)
kısaltılabilir:
A+=B
return 0
ya return 1
eşdeğerdir return False
ya return True
.
-x
yerine x*-1
. --8.32
yerine -8.32*-1
. Ya da sadece 8.32
...
A+=B
B
bir 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
, y
ve b
ayrıca, ifadeler olabilir nota rağmen her iki x
vey
hatta değerlendirilir seçili değilken.
İşte rakam x
ve 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 x
ve bunun yerine olumsuzlama olarak y
yeniden 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()