Apa tips umum yang Anda miliki untuk bermain golf di Python? Saya mencari ide yang dapat diterapkan pada masalah kode-golf dan yang juga setidaknya agak spesifik untuk Python (mis. "Hapus komentar" bukan jawaban).
Silakan kirim satu tip per jawaban.
Jawaban:
Gunakan
a=b=c=0
sebagai gantia,b,c=0,0,0
.Gunakan
a,b,c='123'
sebagai gantia,b,c='1','2','3'
.sumber
Persyaratan bisa panjang. Dalam beberapa kasus, Anda dapat mengganti kondisional sederhana dengan
(a,b)[condition]
. Jikacondition
benar, makab
dikembalikan.Membandingkan
Untuk ini
sumber
a if a<b else b
dana<b and a or b
(lambda(): b, lambda(): a)[a < b]()
buat hubungan arus pendek Anda sendiri dengan lambdasP and A or B
untuk setiap A yang memberibool(A)=False
. Tetapi(P and [A] or [B])[0]
akan melakukan pekerjaan. Lihat diveintopython.net/power_of_introspection/and_or.html untuk referensi.Suatu hal hebat yang pernah saya lakukan adalah:
dari pada:
Operator perbandingan Python mengguncang.
Menggunakan semuanya sebanding dengan Python 2, Anda juga dapat menghindari
and
operator dengan cara ini. Sebagai contoh, jikaa
,b
,c
dand
adalah bilangan bulat,dapat disingkat oleh satu karakter ke:
Ini menggunakan bahwa setiap daftar lebih besar dari bilangan bulat apa pun.
Jika
c
dand
adalah daftar, ini menjadi lebih baik:sumber
3>a>1<b<5
[$a => $b]->[$b <= $a]
:)if(a<b)+(c>d):foo()
*
. Anor
akan menjadi+
foo()if 3>a>1<b<5
Jika Anda menggunakan fungsi bawaan berulang kali, mungkin akan lebih hemat tempat untuk memberinya nama baru, jika menggunakan argumen yang berbeda:
sumber
Terkadang kode Python Anda mengharuskan Anda memiliki 2 tingkat lekukan. Yang jelas harus dilakukan adalah menggunakan satu dan dua ruang untuk setiap level indentasi.
Namun, Python 2 menganggap tab dan karakter spasi sebagai level indentasi yang berbeda.
Ini berarti level indentasi pertama dapat berupa satu spasi dan yang kedua dapat menjadi satu karakter tab.
Sebagai contoh:
Di mana
\t
karakter tab.sumber
TabError: inconsistent use of tabs and spaces in indentation.
Gunakan substitusi string dan
exec
untuk berurusan dengan kata kunci panjang sepertilambda
yang sering diulang dalam kode Anda.String target sangat sering
'lambda '
, yaitu 7 byte. Misalkan cuplikan kode Anda berisin
kejadian'lambda '
, dans
panjang byte. Kemudian:plain
pilihan adalahs
byte panjang.replace
pilihan adalahs - 6n + 29
byte panjang.%
pilihan adalahs - 5n + 22 + len(str(n))
byte panjang.Dari sebidang byte yang disimpan
plain
untuk ketiga opsi ini, kita dapat melihat bahwa:exec"..."%(('lambda ',)*5)
menyimpan 2 byte, dan merupakan pilihan terbaik Anda.exec"...".replace('`','lambda ')
adalah pilihan terbaik Anda.Untuk kasus lain, Anda dapat mengindeks tabel di bawah ini:
Misalnya, jika string
lambda x,y:
(panjang 11) muncul 3 kali dalam kode Anda, Anda lebih baik menulisexec"..."%(('lambda x,y:',)*3)
.sumber
replace
sangat besar.=>
hanya string= lambda
. Misalnya,f=>:0
akanf = lambda: 0
.Gunakan pengirisan panjang untuk memilih satu string dari banyak string
vs.
Dalam case dua-string Boolean ini, kita juga bisa menulis
untuk
Tidak seperti interleaving, ini bekerja untuk string dengan panjang berapa pun, tetapi dapat memiliki masalah prioritas operator jika
b
bukan ekspresi.sumber
for x in ("foo","bar","baz"): print x
x
yang diberikan. Bagian golf adalah"fbboaaorz"[x::3]
vs["foo","bar","baz"][x]
Bagaimanax
nilai didapat akan menjadi bagian lain dari solusi golf Anda.Gunakan
`n`
untuk mengonversi bilangan bulat ke string alih-alih menggunakanstr(n)
:sumber
Menyimpan tabel pencarian sebagai angka ajaib
Katakanlah Anda ingin meng-hardcode tabel pencarian Boolean, seperti yang mana dari dua belas angka pertama bahasa Inggris yang mengandung
n
.Kemudian, Anda bisa mengimplementasikan tabel pencarian ini dengan ringkas sebagai:
dengan hasil
0
atau1
samaFalse
denganTrue
.Idenya adalah bahwa angka ajaib menyimpan tabel sebagai bitstring
bin(3714)
=0b111010000010
, dengann
digit -th (dari ujung) yang sesuai dengann
entri tabel th. Kami mengaksesn
entri th dengan bithiftingn
ruang angka ke kanan dan mengambil digit terakhir&1
.Metode penyimpanan ini sangat efisien. Bandingkan dengan alternatifnya
Anda dapat membuat tabel pencarian Anda menyimpan entri multibit yang dapat diekstraksi seperti
untuk mengekstrak blok empat-bit yang relevan.
sumber
Perkecil dua loop numerik menjadi satu
Katakanlah Anda melakukan iterasi pada sel-sel
m*n
grid Alih-alih duafor
loop bersarang , satu untuk baris dan satu kolom, biasanya lebih pendek untuk menggunakan satu loop untuk beralih di atasm*n
sel - sel grid. Anda bisa mengekstrak baris dan kolom sel di dalam loop.Kode asli:
Kode golf:
Akibatnya, Anda mengulangi produk Cartesian dari dua rentang, menyandikan pasangan
(i,j)
sebagaix=i*n+j
. Anda telah menyimpanrange
panggilan mahal dan tingkat lekukan di dalam loop. Urutan iterasi tidak berubah.Gunakan
//
daripada/
di Python 3. Jika Anda merujuki
danj
berkali-kali, mungkin lebih cepat untuk menetapkan nilainyai=k/n
,j=k%n
di dalam loop.sumber
for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
n
loop: repl.it/EHwaitertools.product
bisa jauh lebih ringkas daripada loop bersarang, terutama ketika menghasilkan produk cartesian.a1, a2, b1, b2
adalah contoh dari produk kartesius'ab'
dan'12'
Kecuali jika token berikut dimulai dengan
e
atauE
. Anda dapat menghapus ruang mengikuti nomor.Misalnya:
Menjadi:
Menggunakan ini dalam pernyataan satu baris yang rumit dapat menyimpan beberapa karakter.
EDIT: seperti yang ditunjukkan @marcog,
4or a
akan berfungsi, tetapi tidaka or4
karena ini akan membingungkan dengan nama variabel.sumber
if(i,j)==(4,4):
bahkan lebih pendek dan dalam kasus khusus iniif i==j==4:
4or a
bekerja, tetapi tidaka or4
0or
juga tidak berfungsi (0o
merupakan awalan untuk angka oktal).0 or x
selalu akan kembalix
. Mungkin juga memotong0 or
.0or
baik-baik saja sebagai bagian dari angka yang lebih lama.10 or x
setara dengan10or x
.Untuk integer
n
, Anda bisa menulisn+1
sebagai-~n
n-1
sebagai~-n
karena bit flip
~x
sama dengan-1-x
. Ini menggunakan jumlah karakter yang sama, tetapi secara tidak langsung dapat memotong spasi atau paren sebagai prioritas operator.Membandingkan:
Operator
~
dan unary-
yang diutamakan lebih tinggi dari*
,/
,%
, tidak seperti biner+
.sumber
-~-x
menghemat satu byte vs(1-x)
.a+b+1
dapat ditulis secara lebih ringkasa-~b
.n-i-1
itu adiln+~i
.Cara yang bagus untuk mengonversi iterable ke daftar di Python 3 :
bayangkan Anda memiliki beberapa iterable, like
Tetapi Anda perlu daftar:
Sangat berguna untuk membuat daftar karakter dari string
sumber
*s,='abcde'
dan kemudians
crash python3 interaktif saya dengan segfault :([*'abcde']
.Alih-alih
range(x)
, Anda dapat menggunakan*
operator pada daftar apa pun, jika Anda tidak benar-benar perlu menggunakan nilaii
:sebagai lawan
Jika Anda perlu melakukan ini lebih dari dua kali, Anda bisa menetapkan setiap iterable ke variabel, dan gandakan variabel itu dengan rentang yang Anda inginkan:
Catatan : ini seringkali lebih lama daripada
exec"pass;"*8
, jadi trik ini seharusnya hanya digunakan ketika itu bukan pilihan.sumber
[1]*8
lebih pendek daripadarange(8)
, Anda juga bisa menghemat ruang karenafor i in[...
legal sementarafor i in range...
tidak".exec"pass;"*8
secara signifikan lebih pendek.r=1
,r*8
adalah 8, dan Anda tidak dapat mengulangi melalui nomor. Saya kira Anda maksudr=[1]
Anda dapat menggunakan wajah smiley alien yang lama untuk membalik urutan:
sumber
Pembongkaran yang diperpanjang iterable ("Penugasan berbintang", hanya Python 3)
Cara terbaik untuk menjelaskan ini adalah melalui contoh:
Kami telah melihat manfaatnya - mengubah iterable menjadi daftar dengan Python 3 :
Berikut adalah beberapa kegunaan lagi.
Mendapatkan elemen terakhir dari daftar
Dalam beberapa situasi, ini juga dapat digunakan untuk mendapatkan elemen pertama untuk menghemat parens:
Menetapkan daftar kosong dan variabel lainnya
Menghapus elemen pertama atau terakhir dari daftar yang tidak kosong
Ini lebih pendek dari alternatif
L=L[1:]
danL.pop()
. Hasilnya juga dapat disimpan ke daftar yang berbeda.Kiat milik @grc
sumber
a=1;L=[]
berkali-kali. Sungguh menakjubkan bahwa Anda dapat menyimpan karakter pada sesuatu yang sangat mudah seperti ini.a,*L=1,
), tetapi masih menyimpan satu char :)a,*_,b=L
atur literal dalam Python2.7
Anda dapat menulis set seperti ini
S={1,2,3}
Ini juga berarti Anda dapat memeriksa keanggotaan menggunakan{e}&S
alih-alihe in S
yang menyimpan satu karakter.sumber
if
s karena tidak ada spasi (if{e}&S:
)not in
dengan{e}-S
dengan trik yangSelama berabad-abad itu mengganggu saya bahwa saya tidak bisa memikirkan cara singkat untuk mendapatkan seluruh alfabet. Jika Anda menggunakan
range
cukup yangR=range
layak dimiliki dalam program Anda, makalebih pendek dari yang naif
, tapi selain itu lebih panjang dengan satu karakter. Itu menghantui saya bahwa yang pandai yang membutuhkan pengetahuan tentang nilai-nilai ascii akhirnya menjadi lebih bertele-tele daripada hanya mengetik semua huruf.
Sampai saya melihat jawaban ini untuk My Daughter's Alphabet . Saya tidak bisa mengikuti riwayat sunting dengan cukup baik untuk mengetahui apakah jenius ini adalah karya OP atau apakah itu adalah saran dari seorang komentator, tetapi ini (saya percaya) adalah cara terpendek untuk membuat iterable dari 26 huruf dalam alfabet Romawi.
Jika huruf besar tidak penting, Anda dapat menghapus karakter lain dengan menggunakan huruf besar:
Saya menggunakan
map
terlalu banyak, saya tidak tahu bagaimana ini tidak pernah terjadi pada saya.sumber
string.lowercase
- itulah gunanya .ord('z')
)? Selain panjangnya sama ... Selain itu, jika Anda membutuhkan alfanumerik, gantistr.isalpha
dengan versi @ quintopia denganstr.isalnum
. (Tetapi jika Anda hanya membutuhkan satu kasing, seluruh string 36-karakter tidak lebih darifilter(str.isalnum,map(chr,range(90)))
.)R
, versi saya lebih pendek daripada yang asli:'%c'*26%tuple(R(97,123))
(hanya 24 karakter) jika Anda mengejarange
itu asalkan alfabet - versi huruf besar lebih pendekMeskipun python tidak memiliki pernyataan peralihan, Anda dapat meniru mereka dengan kamus. Misalnya, jika Anda menginginkan sakelar seperti ini:
Anda bisa menggunakan
if
pernyataan, atau Anda bisa menggunakan ini:atau ini:
yang lebih baik jika semua jalur kode berfungsi dengan parameter yang sama.
Untuk mendukung nilai default, lakukan ini:
(atau ini:)
Satu keuntungan lain dari hal ini adalah bahwa jika Anda memang memiliki kelebihan, Anda bisa menambahkannya setelah akhir kamus:
Dan jika Anda hanya ingin menggunakan sakelar untuk mengembalikan nilai:
Anda bisa melakukan ini:
sumber
dict(s1=v1,s2=v2,...,sn=vn)
alih-alih{'s1':v1,'s2':v2,...,'sn':vn}
menyimpan 2 * n-4 byte dan lebih baik jika n> = 3Ketika Anda memiliki dua nilai boolean,
a
danb
, jika Anda ingin mengetahui apakah keduanyaa
danb
itu benar, gunakan*
sebagai gantiand
:vs.
jika salah satu nilai salah, itu akan mengevaluasi seperti
0
dalam pernyataan itu, dan nilai integer hanya benar jika bukan nol.sumber
&
:a=b=False
,a&b
+
untukor
jika Anda bisa menjamina != -b
|
berfungsi dalam semua situasi.*
bukannyaand
/&&
menyimpan beberapa byte dalam banyak bahasa.Mengeksploitasi representasi string Python 2
Python 2 memungkinkan Anda mengonversi objek
x
ke representasi string`x`
dengan biaya hanya 2 karakter. Gunakan ini untuk tugas-tugas yang lebih mudah dilakukan pada string objek daripada objek itu sendiri.Gabung karakter
Diberikan daftar karakter
l=['a','b','c']
, seseorang dapat menghasilkan''.join(l)
sebagai`l`[2::5]
, yang menyimpan byte.Alasannya adalah bahwa
`l`
ini"['a', 'b', 'c']"
(dengan spasi), sehingga seseorang dapat mengekstrak huruf dengan daftar slice, mulai bahwa karakter nol-diindeks keduaa
, dan mengambil setiap karakter kelima dari sana. Ini tidak berfungsi untuk bergabung dengan string multi-karakter atau karakter melarikan diri yang diwakili seperti'\n'
.Digit gabungan
Demikian pula, diberikan daftar non-kosong digit seperti
l=[0,3,5]
, seseorang dapat menggabungkannya ke dalam string'035'
sebagai`l`[1::3]
.Ini menghemat melakukan sesuatu seperti
map(str,l)
. Perhatikan bahwa mereka harus berupa digit tunggal, dan tidak dapat mengapung seperti1.0
dicampur. Juga, ini gagal pada daftar kosong, menghasilkan]
.Periksa negatif
Sekarang, untuk tugas non-string. Misalkan Anda memiliki daftar
l
bilangan real dan ingin menguji apakah itu berisi bilangan negatif, menghasilkan Boolean.Anda dapat melakukan
yang memeriksa tanda negatif pada rep string. Ini lebih pendek dari salah satu dari
Untuk yang kedua,
min(l)<0
akan gagal pada daftar kosong, jadi Anda harus melakukan lindung nilai.sumber
str(l)[2::5]
adalah 12 byte, berbanding 19 untuk''.join(map(str,l))
. Situasi aktual di mana ini muncul (di manal
pernyataan generator, bukan daftar) menyelamatkan saya hanya satu byte ... yang masih layak!Fungsi satu baris dapat dilakukan dengan lambda:
dapat dikonversi ke (perhatikan ruang yang hilang
3and
dan10or
)sumber
c=lambda a:a+[-5,10][a<3]
. trik dan / atau lebih berguna ketika Anda bergantung pada perilaku shortcircuitelse:
bisa dijatuhkan sebagaireturn
menghentikan eksekusi fungsi, jadi semua yang mengikuti hanya dieksekusi jikaif
kondisinya gagal, alias jikaelse
kondisinya benar. Dengan demikianelse
dapat dihilangkan dengan aman. (Dijelaskan secara terperinci untuk orang-orang baru di luar sana)c=lambda a:a-5+15*(a<3)
loop hingga 4 item mungkin lebih baik untuk memasok tuple daripada menggunakan rentang
vs.
sumber
Ceil dan Lantai
Jika Anda ingin mendapatkan hasil pembulatan untuk divisi, seperti yang Anda lakukan dengan
//
lantai, Anda bisa menggunakanmath.ceil(3/2)
untuk 15 atau yang lebih pendek-(-3//2)
untuk 8 byte.sumber
n//1+1
bukannya ceil tetapi itu berarti ceil (n) = n +1 tetapi itu harus bekerja untuk semua nilai non integerround(x)
adalah(x+.5)//1
, +1 byte tetapi yang terakhir dimulai dengan a(
, dan jikax
jumlah yang terdiri dari konstanta dapat berguna.Gunakan
+=
sebagai gantiappend
danextend
dapat disingkat menjadi:
B,
di sini membuat tupel satu elemen yang dapat digunakan untuk memperluasA
seperti[B]
diA+=[B]
.dapat disingkat menjadi:
sumber
return 0
ataureturn 1
setara denganreturn False
ataureturn True
.-x
bukannyax*-1
.--8.32
bukannya-8.32*-1
. Atau hanya8.32
...A+=B
B
adalah atuple
.Memilih satu dari dua angka berdasarkan suatu syarat
Anda sudah tahu untuk menggunakan pemilihan daftar
[x,y][b]
dengan Booleanb
untuk ekspresi ternaryy if b else x
. Variabelx
,,y
danb
juga bisa menjadi ekspresi, meskipun perhatikan bahwa keduanyax
dany
dievaluasi bahkan ketika tidak dipilih.Berikut beberapa potensi pengoptimalan kapan
x
dany
sedang angka.[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
(atauy-z*b
), di mana z = yx.Anda juga dapat beralih
x
dany
jika Anda dapat menulis ulangb
menjadi negasi sebagai gantinya.sumber
Gunakan ~ untuk mengindeks dari bagian belakang daftar
Jika
L
daftar, gunakanL[~i]
untuk mendapatkani
elemen 'th dari belakang.Ini adalah
i
elemen kebalikan dariL
. Bit komplemen~i
sama dengan-i-1
, dan memperbaiki kesalahan off-by-one dariL[-i]
.sumber
PEP448 - Generalisasi Pembongkaran Tambahan
Dengan dirilisnya Python 3.5 , manipulasi daftar, tupel, set, dan dikt baru saja menjadi pemain golf.
Mengubah iterable menjadi set / list
Bandingkan pasangan:
Jauh lebih pendek! Namun, perlu diketahui bahwa jika Anda hanya ingin mengonversi sesuatu ke daftar dan menetapkannya ke variabel, pembongkaran yang dapat diperpanjang yang normal lebih pendek:
Sintaks yang sama berfungsi untuk tupel:
yang seperti diperpanjang membongkar iterable, tetapi dengan tanda bintang dan koma di sisi lain.
Bergabung daftar / tupel
Pembongkaran sedikit lebih pendek daripada penggabungan jika Anda perlu menambahkan daftar / tuple ke kedua sisi:
Mencetak isi beberapa daftar
Ini tidak terbatas pada
print
, tapi itu pasti dari mana sebagian besar jarak tempuh akan datang. PEP448 sekarang memungkinkan untuk beberapa pembongkaran, seperti:Memperbarui beberapa item kamus
Ini mungkin tidak akan sering terjadi, tetapi sintaksis dapat digunakan untuk menghemat memperbarui kamus jika Anda memperbarui setidaknya tiga item:
Ini pada dasarnya meniadakan kebutuhan
dict.update
.sumber
Ubah
import *
keimport*
Jika Anda belum pernah mendengar,
import*
simpan karakter!hanya 1 karakter lebih panjang dari
import math as m
dan Anda bisa menghapus semua instance darim.
Bahkan satu kali penggunaan adalah penghemat!
sumber
jika nilai saya tidak berguna:
atau
sumber
for i in[0]*x:s+=input()
untuk menghemat ruang lain. Selain itu, Anda dapat menghapus spasi antara eksekutif dan tanda kutip pertama untuk mendapatkannyaexec's+=input();'*x
for i in[0]*x:s+=input()