Jakie masz ogólne wskazówki na temat gry w golfa w Pythonie? Szukam pomysłów, które można zastosować do problemów związanych z golfem i które są przynajmniej w pewnym stopniu specyficzne dla Pythona (np. „Usuń komentarze” nie jest odpowiedzią).
Proszę zamieścić jedną wskazówkę na odpowiedź.
Odpowiedzi:
Użyj
a=b=c=0
zamiasta,b,c=0,0,0
.Użyj
a,b,c='123'
zamiasta,b,c='1','2','3'
.źródło
Warunki warunkowe mogą być długie. W niektórych przypadkach możesz zamienić prosty warunek na
(a,b)[condition]
. Jeślicondition
jest prawdą, tob
jest zwracane.Porównać
Do tego
źródło
a if a<b else b
ia<b and a or b
(lambda(): b, lambda(): a)[a < b]()
zrób własne zwarcie z lambdasP and A or B
każde A, które dajebool(A)=False
. Ale(P and [A] or [B])[0]
wykona zadanie. Zobacz diveintopython.net/power_of_introspection/and_or.html w celach informacyjnych.Świetną rzeczą, którą kiedyś zrobiłem, jest:
zamiast:
Operatory porównania Pythona działają jak skała.
Używając tego, że wszystko jest porównywalne w Pythonie 2, możesz w
and
ten sposób uniknąć operatora. Na przykład, jeślia
,b
,c
id
są liczbami całkowitymi,można skrócić o jedną postać do:
Dzięki temu każda lista jest większa niż dowolna liczba całkowita.
Jeśli
c
id
są listami, staje się to jeszcze lepsze:źródło
3>a>1<b<5
[$a => $b]->[$b <= $a]
:)if(a<b)+(c>d):foo()
*
.or
Byłoby+
foo()if 3>a>1<b<5
Jeśli wielokrotnie używasz wbudowanej funkcji, nadanie jej nowej nazwy może być bardziej zajmujące miejsce, jeśli używasz różnych argumentów:
źródło
Czasami kod Pythona wymaga 2 poziomów wcięcia. Oczywistą rzeczą do zrobienia jest użycie jednej i dwóch spacji dla każdego poziomu wcięcia.
Jednak Python 2 uważa znaki tabulacji i spacji za różne poziomy wcięcia.
Oznacza to, że pierwszy poziom wcięcia może mieć jedną spację, a drugi może być znakiem tabulacji.
Na przykład:
Gdzie
\t
jest znak tabulacji.źródło
TabError: inconsistent use of tabs and spaces in indentation.
Używaj podstawiania ciągów,
exec
aby radzić sobie z długimi słowami kluczowymi,lambda
które są często powtarzane w kodzie.Łańcuch docelowy ma bardzo często
'lambda '
długość 7 bajtów. Załóżmy, że fragment kodu zawieran
wystąpień'lambda '
i jests
bajtów. Następnie:plain
Opcja jests
bajtów.replace
Opcja jests - 6n + 29
bajtów.%
Opcja jests - 5n + 22 + len(str(n))
bajtów.Z wykresu bajtów zapisanych
plain
dla tych trzech opcji możemy zobaczyć, że:exec"..."%(('lambda ',)*5)
oszczędza 2 bajty i jest najlepszą opcją.exec"...".replace('`','lambda ')
jest najlepszą opcją.W innych przypadkach możesz zindeksować poniższą tabelę:
Na przykład, jeśli ciąg
lambda x,y:
(długość 11) występuje w kodzie 3 razy, lepiej pisaćexec"..."%(('lambda x,y:',)*3)
.źródło
replace
jest ogromny.=>
to tylko ciąg= lambda
. Na przykładf=>:0
byłobyf = lambda: 0
.Użyj rozszerzonego krojenia, aby wybrać jeden ciąg z wielu
vs
W tym logicznym dwuczęściowym przypadku można również pisać
dla
W przeciwieństwie do przeplatania, działa to na ciągi dowolnej długości, ale może mieć problemy z pierwszeństwem operatora, jeśli
b
zamiast tego jest wyrażeniem.źródło
for x in ("foo","bar","baz"): print x
x
renderowane są różne wartości . Część golfowa jest"fbboaaorz"[x::3]
vs["foo","bar","baz"][x]
Sposób obliczaniax
wartości byłby kolejną częścią twojego rozwiązania golfowego.Służy
`n`
do konwersji liczby całkowitej na ciąg zamiast używaniastr(n)
:źródło
Przechowuj tabele odnośników jako magiczne liczby
Załóżmy, że chcesz na stałe zakodować boolowską tablicę wyszukiwania, na przykład, która z pierwszych dwunastu angielskich liczb zawiera
n
.Następnie możesz zwięźle zaimplementować tę tabelę wyszukiwania:
z wynikającymi
0
lub1
jest równaFalse
sięTrue
.Chodzi o to, że magiczna liczba przechowuje tabelę jako ciąg bitów
bin(3714)
=0b111010000010
, przy czymn
-ta cyfra (od końca) odpowiadan
th pozycji tablicy. Dostęp don
tego wpisu uzyskujemy poprzez przesunięcie bitówn
w prawo spacji numerycznych i zabranie ostatniej cyfry o&1
.Ta metoda przechowywania jest bardzo wydajna. Porównaj z alternatywami
Możesz mieć swoje wpisy multibitowe w tabeli odnośników, które można wyodrębnić
aby wyodrębnić odpowiedni czterobitowy blok.
źródło
Zwiń dwie pętle numeryczne w jedną
Powiedzmy, że iterujesz po komórkach
m*n
siatki. Zamiast dwóch zagnieżdżonychfor
pętli, jednej dla wiersza i jednej kolumny, zwykle krótsze jest użycie pojedynczej pętli do iteracji pom*n
komórkach siatki. Możesz wyodrębnić wiersz i kolumnę komórki wewnątrz pętli.Oryginalny kod:
Kod do gry w golfa:
W efekcie iterujesz nad iloczynem kartezjańskim dwóch zakresów, kodując parę
(i,j)
jakox=i*n+j
. Zapisałeś kosztownerange
połączenie i poziom wcięcia w pętli. Kolejność iteracji pozostaje niezmieniona.Użyj
//
zamiast/
w Pythonie 3. Jeżeli dotycząi
ij
wiele razy, może być szybciej przypisać ich wartościi=k/n
,j=k%n
wewnątrz pętli.źródło
for i in range(m*n*o): do_stuff(i/n/o,i%(n*o)/o,i%o)
n
pętli: repl.it/EHwaitertools.product
mogą być znacznie bardziej zwięzłe niż pętle zagnieżdżone, szczególnie podczas generowania produktów kartezjańskich.a1, a2, b1, b2
są przykładami kartezjańskiego produktu'ab'
i'12'
Chyba że następujący token zaczyna się od
e
lubE
. Możesz usunąć spację po numerze.Na przykład:
Staje się:
Używanie tego w skomplikowanych instrukcjach jednowierszowych może zaoszczędzić sporo znaków.
EDYCJA: jak wskazał @marcog,
4or a
będzie działać, ale nie,a or4
ponieważ jest to mylone z nazwą zmiennej.źródło
if(i,j)==(4,4):
jest jeszcze krótszy, aw tym szczególnym przypadkuif i==j==4:
4or a
działa, ale niea or4
0or
też nie działa (0o
jest prefiksem liczb ósemkowych).0 or x
zawsze wrócix
. Równie dobrze można wyciąć0 or
.0or
jest w porządku, jako część dłuższej liczby.10 or x
jest równoważne z10or x
.W przypadku liczb całkowitych
n
możesz pisaćn+1
tak jak-~n
n-1
tak jak~-n
ponieważ bit flip
~x
jest równy-1-x
. Używa tej samej liczby znaków, ale może pośrednio wycinać spacje lub pareny dla pierwszeństwa operatora.Porównać:
Operatorzy
~
i jednoskładnikowa-
jest wyższy priorytet niż*
,/
,%
w przeciwieństwie do binarnego+
.źródło
-~-x
oszczędza jeden bajt Vs.(1-x)
.a+b+1
można ją bardziej zwięźle napisać jakoa-~b
.n-i-1
jest po prostun+~i
.Dobry sposób na przekonwertowanie iterowalnej listy na Python 3 :
wyobraź sobie, że masz jakieś iterowalne
Ale potrzebujesz listy:
Bardzo przydatne jest utworzenie listy znaków z łańcucha
źródło
*s,='abcde'
a następnies
zawiesza moje interaktywne python3 z segfault :([*'abcde']
.Zamiast
range(x)
możesz użyć*
operatora na liście czegokolwiek, jeśli tak naprawdę nie musisz używać wartościi
:w przeciwieństwie do
Jeśli musisz to zrobić więcej niż dwa razy, możesz przypisać dowolną iterowalną zmienną i pomnożyć tę zmienną przez żądany zakres:
Uwaga : często jest on dłuższy niż
exec"pass;"*8
, więc tej sztuczki należy używać tylko wtedy, gdy nie jest to możliwe.źródło
[1]*8
są one krótsze niżrange(8)
, możesz także zaoszczędzić miejsce, ponieważfor i in[...
jest to legalne, podczas gdyfor i in range...
nie jest”.exec"pass;"*8
jest znacznie krótszy.r=1
,r*8
wynosi 8, i nie można iterować przez liczbę. Chyba miałeś na myślir=[1]
Możesz użyć starej dobrej obcej buźki do odwrócenia sekwencji:
źródło
Rozszerzone iterowalne rozpakowywanie („ gwiazdką”, tylko Python 3)
Najlepszym sposobem na wyjaśnienie tego jest przykład:
Widzieliśmy już zastosowanie tego - przekształcenie iterowalnej listy w Python 3 :
Oto kilka innych zastosowań.
Pobieranie ostatniego elementu z listy
W niektórych sytuacjach można tego również użyć do uzyskania pierwszego elementu zapisanego na parens:
Przypisywanie pustej listy i innych zmiennych
Usuwanie pierwszego lub ostatniego elementu niepustej listy
Są one krótsze niż alternatywy
L=L[1:]
iL.pop()
. Wynik można również zapisać na innej liście.Porady dzięki uprzejmości @grc
źródło
a=1;L=[]
tyle razy. To niesamowite, że możesz zapisywać znaki na czymś tak prostym jak to.a,*L=1,
), ale wciąż oszczędza jeden znak :)a,*_,b=L
ustaw literały w Python2.7
Możesz pisać takie zestawy.
S={1,2,3}
Oznacza to również, że możesz sprawdzić członkostwo, używając,{e}&S
zamiaste in S
którego zapisujesz jedną postać.źródło
if
s, ponieważ nie ma spacji (if{e}&S:
)not in
go{e}-S
tą sztuczkąPrzez wieki martwiło mnie, że nie mogę wymyślić krótkiego sposobu na zdobycie całego alfabetu. Jeśli wykorzystasz
range
wystarczającą ilość, którąR=range
warto mieć w swoim programie, tojest krótszy niż naiwny
, ale poza tym jest dłuższy o jedną postać. Prześladowało mnie to, że ta mądra, która wymagała pewnej wiedzy o wartościach ascii, okazała się bardziej gadatliwa niż tylko pisanie wszystkich liter.
Dopóki nie zobaczyłem tę odpowiedź dla Alfabet mojej córki . Nie mogę śledzić historii edycji wystarczająco dobrze, aby dowiedzieć się, czy ten geniusz był dziełem OP, czy też sugestią komentatora, ale jest to (jak sądzę) najkrótsza droga do stworzenia iterowalnej z 26 liter alfabetem rzymskim.
Jeśli wielkość liter nie ma znaczenia, możesz usunąć inną postać, używając wielkich liter:
Używam
map
zdecydowanie za dużo, nie wiem, jak mi się to nigdy nie zdarzyło.źródło
string.lowercase
- po to jest.ord('z')
)? Oprócz tego, że ma taką samą długość ... Jeśli potrzebujesz alfanumerycznych, zamieństr.isalpha
w wersji @ quintopia nastr.isalnum
. (Ale jeśli potrzebujesz tylko jednego przypadku, cały ciąg 36 znaków nie jest dłuższy niżfilter(str.isalnum,map(chr,range(90)))
.)R
, moja wersja jest krótsza niż oryginalna:'%c'*26%tuple(R(97,123))
(tylko 24 znaki), jeśli przeliterujeszrange
, jest ona tak długa, jak alfabet - wersja z dużymi literami jest krótszaChociaż python nie ma instrukcji switch, możesz emulować je za pomocą słowników. Na przykład, jeśli chcesz taki przełącznik:
Możesz użyć
if
instrukcji lub możesz użyć tego:albo to:
co jest lepsze, jeśli wszystkie ścieżki kodu są funkcjami o tych samych parametrach.
Aby wesprzeć wartość domyślną:
(albo to:)
Inną zaletą tego jest to, że jeśli masz zwolnienia, możesz je dodać po zakończeniu słownika:
A jeśli chcesz użyć przełącznika do zwrócenia wartości:
Możesz po prostu to zrobić:
źródło
dict(s1=v1,s2=v2,...,sn=vn)
zamiast{'s1':v1,'s2':v2,...,'sn':vn}
zapisuje 2 * n-4 bajtów i lepiej, jeśli n> = 3Kiedy masz dwie wartości logicznych,
a
ab
jeśli chcesz dowiedzieć się, czy obaa
ib
są prawdziwe, użyj*
zamiastand
:vs
jeśli którakolwiek z wartości jest fałszywa, zostanie obliczona jak
0
w tej instrukcji, a wartość całkowita jest prawdziwa tylko wtedy, gdy jest niezerowa.źródło
&
:a=b=False
,a&b
+
dlaor
jeśli można zagwarantowaća != -b
|
działa we wszystkich sytuacjach.*
zamiastand
/&&
zapisuje niektóre bajty w wielu językach.Wykorzystaj ciągi znaków w języku Python 2
Python 2 pozwala przekonwertować obiekt
x
na jego reprezentację ciągu`x`
ciągu kosztem tylko 2 znaków. Użyj tego do zadań, które łatwiej wykonać na łańcuchu obiektu niż na samym obiekcie.Dołącz do postaci
Biorąc pod uwagę listę znaków
l=['a','b','c']
, można utworzyć''.join(l)
as`l`[2::5]
, co oszczędza bajt.Powodem jest to, że
`l`
jest"['a', 'b', 'c']"
(ze spacjami), więc można wyodrębnić litery z plasterka listy, zaczynając że drugie zero-indeksowane charaktera
, biorąc co piąty znak stamtąd. Nie działa to w przypadku łączenia ciągów wieloznakowych lub znaków zastępczych przedstawionych jako'\n'
.Połącz cyfry
Podobnie, biorąc pod uwagę niepustą listę cyfr, takich jak
l=[0,3,5]
, można połączyć je w ciąg znaków'035'
jako`l`[1::3]
.To oszczędza robienie czegoś takiego
map(str,l)
. Zauważ, że muszą być one jednocyfrowe i nie mogą mieć liczb zmiennoprzecinkowych, takich jak1.0
pomieszane. Ponadto nie powiodło się to na pustej liście, powodując powstanie]
.Sprawdź negatywne
Teraz dla zadania nieciągłego. Załóżmy, że masz listę
l
liczb rzeczywistych i chcesz sprawdzić, czy zawiera ona liczby ujemne, co daje wartość logiczną.Możesz to zrobić
który sprawdza znak ujemny w rep. To krócej niż którykolwiek z nich
Po drugie,
min(l)<0
nie powiedzie się na pustej liście, więc musisz się zabezpieczyć.źródło
str(l)[2::5]
wynosi 12 bajtów w porównaniu z 19 dla''.join(map(str,l))
. Rzeczywista sytuacja, w której to się wydarzyło (gdziel
była instrukcja generatora, a nie lista) zaoszczędziła mi tylko jeden bajt ... co wciąż jest tego warte!Jednowierszową funkcję można wykonać za pomocą lambda:
można przekonwertować na (zwróć uwagę na brak miejsca
3and
i10or
)źródło
c=lambda a:a+[-5,10][a<3]
. sztuczka i / lub trik jest bardziej przydatna, gdyelse:
można ją usunąć, ponieważreturn
zatrzymuje wykonywanie funkcji, więc wszystko, co następuje, jest wykonywane tylko wtedy, gdyif
warunek się nie powiedzie, czyli jeślielse
warunek jest prawdziwy. W ten sposóbelse
można bezpiecznie pominąć. (Wyjaśnione szczegółowo dla neofitów na zewnątrz)c=lambda a:a-5+15*(a<3)
Pętle składające się z maksymalnie 4 przedmiotów mogą być lepsze niż kratka
vs
źródło
Sufit i podłoga
Jeśli kiedykolwiek chcesz uzyskać zaokrąglony wynik dla podziału, podobnie jak w
//
przypadku podłogi, możesz użyćmath.ceil(3/2)
dla 15 lub znacznie krótszego-(-3//2)
dla 8 bajtów.źródło
n//1+1
zamiast ceil, ale to znaczy ceil (n) = n + 1, ale powinno działać dla wszystkich wartości niecałkowitychround(x)
to(x+.5)//1
+1 bajt, ale ten ostatni zaczyna się od a(
, a jeślix
suma składająca się ze stałej może być użyteczna.Użyj
+=
zamiastappend
iextend
można skrócić do:
B,
tutaj tworzy krotkę jednoelementową, której można użyć do rozszerzeniaA
tak jak[B]
wA+=[B]
.można skrócić do:
źródło
return 0
lubreturn 1
jest równoważne zreturn False
lubreturn True
.-x
raczej niżx*-1
.--8.32
raczej niż-8.32*-1
. Lub po prostu8.32
...A+=B
B
totuple
.Wybór jednej z dwóch liczb na podstawie warunku
Wiesz już, że możesz używać wyboru listy
[x,y][b]
z wartością logicznąb
dla wyrażenia trójskładnikowegoy if b else x
. Zmiennex
,y
ib
może być także wyrażenia, choć pamiętać, że zarównox
iy
oceniane są nawet wtedy, gdy nie wybrano.Oto kilka potencjalnych optymalizacje kiedy
x
iy
są liczbami.[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
(luby-z*b
), gdzie z = yx.Możesz także przełączyć
x
iy
jeśli możesz przepisać,b
aby być jego zaprzeczeniem.źródło
Użyj ~, aby zindeksować z tyłu listy
Jeśli
L
jest to lista, użyj,L[~i]
aby uzyskać teni
czwarty element z tyłu.To jest
i
czwarty element na odwrocieL
. Uzupełnienie bitu~i
jest równe-i-1
, a więc naprawia błąd off-by-one zL[-i]
.źródło
PEP448 - Dodatkowe uogólnienia dotyczące rozpakowywania
Wraz z wydaniem Python 3.5 manipulowanie listami, krotkami, setami i dyktami stało się bardziej golfowe.
Przekształcanie iterowalnego zestawu / listy
Porównaj pary:
Znacznie krócej! Pamiętaj jednak, że jeśli chcesz po prostu przekonwertować coś na listę i przypisać ją do zmiennej, normalne rozszerzone iterowalne rozpakowywanie jest krótsze:
Podobna składnia działa dla krotek:
co jest jak rozszerzone iterowalne rozpakowywanie, ale z gwiazdką i przecinkiem po drugiej stronie.
Łączenie list / krotek
Rozpakowanie jest nieco krótsze niż konkatenacja, jeśli musisz dołączyć listę / krotkę po obu stronach:
Drukowanie zawartości wielu list
Nie jest to ograniczone do
print
, ale zdecydowanie jest to, skąd będzie pochodzić większość przebiegów. PEP448 pozwala teraz na wielokrotne rozpakowywanie, tak jak:Aktualizowanie wielu pozycji słownika
Prawdopodobnie nie zdarza się to często, ale można użyć składni, aby zaoszczędzić na aktualizowaniu słowników, jeśli aktualizujesz co najmniej trzy elementy:
Zasadniczo neguje to jakąkolwiek potrzebę
dict.update
.źródło
Zmień
import *
naimport*
Jeśli nie słyszałeś,
import*
zapisuje znaki!jest tylko 1 znak dłuższy niż
import math as m
i możesz usunąć wszystkie wystąpieniam.
Nawet jednorazowe użycie to oszczędność!
źródło
jeśli wartość i jest bezużyteczna:
lub
źródło
for i in[0]*x:s+=input()
aby zaoszczędzić kolejne miejsce. Możesz także usunąć spację między exec a pierwszym znakiem cudzysłowu, aby uzyskaćexec's+=input();'*x
for i in[0]*x:s+=input()