Jakie masz ogólne wskazówki na temat gry w golfa w Julii? Szukam pomysłów, które można by zastosować do problemów z golfem w kodzie, które są przynajmniej nieco specyficzne dla Julii (np. „Usuń komentarze” nie jest odpowiedzią).
Jakie masz ogólne wskazówki na temat gry w golfa w Julii? Szukam pomysłów, które można by zastosować do problemów z golfem w kodzie, które są przynajmniej nieco specyficzne dla Julii (np. „Usuń komentarze” nie jest odpowiedzią).
Odpowiedzi:
UWAGA: poniżej może zawierać kilka przestarzałych wskazówek, ponieważ Julia nie jest jeszcze całkowicie ustabilizowana pod względem struktury.
Kilka sztuczek, aby uratować kilka postaci
\ =div, a następnie możesz wpisać a\bzamiast div(a,b). Zwróć uwagę na spację - jest to konieczne, aby uniknąć parsowania jako operatora „\ =”. Należy również pamiętać, że w przypadku przeciążenia na poziomie monitu REPL użyj (\)=Base.(\)lub, \ =Base. \aby go zresetować. UWAGA: niektóre funkcje mają wstępnie zdefiniowane istniejące operatory UTF-8, takie jak ÷dla div, jak zauważył Alex A.a>0?"Hi":""używać "Hi"^(a>0)do zapisania jednego bajtu, lub dla wartości logicznej a, "Hi"^ado zapisania trzech bajtów.a=split("Hi there"," ")być w stanie uniknąć a[1]i a[2]za pomocą a,b=split("Hi there"," "), które można określić jako ai b, oszczędzając trzy bajty dla każdego użycia, kosztem tylko dwóch dodatkowych znaków przy przypisaniu. Oczywiście nie rób tego, jeśli możesz pracować z operacjami wektorowymi.[] - w przypadku tablic wyrażenie A[]jest równoważne z A[1]. Zauważ, że nie działa to dla Ciągów, jeśli chcesz zdobyć pierwszą postać, lub dla Tuples.==[]dla tablic i ==()krotek; podobnie, dla negatywu, użyj !=[]i !=(). W przypadku łańcuchów używaj ==""dla pustych, ale używaj >""dla niepustych, ponieważ „” jest leksykograficznie przed każdym innym ciągiem.x<=1&&"Hi"można zapisać jako x>1||"Hi", zapisując znak (o ile powrót wartości logicznej nie jest ważny).in('^',s)raczej niż contains(s,"^"). Jeśli możesz użyć innych znaków, możesz zaoszczędzić nieco więcej '^'∈s, ale pamiętaj, że ∈w UTF-8 jest to 3 bajty.minimum(x)lub maximum(x), użyj min(x...)lub max(x...), aby zgolić jeden znak z twojego kodu, jeśli wiesz, że xbędą miały co najmniej dwa elementy. Alternatywnie, jeśli wiesz, że wszystkie elementy xbędą nieujemne, użyj minabs(x)lubmaxabs(x)r"(?m)match^ this", pisz r"match^ this"m, zachowując trzy znaki.reverse(x)jest o jeden bajt dłuższy flipud(x)i wykona tę samą operację, więc ta druga jest lepsza.{[1,2]}nie {1,2}) - w przypadku Julii 0.4 byłoby to potrzebne Any[[1,2]].endindeksowania tablic, automatycznie jest konwertowany na długość tablicy / łańcucha. Zamiast tego k=length(A)użyj, A[k=end]aby zapisać 3 znaki. Pamiętaj, że może to nie być korzystne, jeśli chcesz natychmiast użyć k. Działa to również w przypadku wielowymiarowym -A[k=end,l=end] otrzyma rozmiar każdego wymiaru A- jednak (k,l)=size(A)w tym przypadku jest krótszy o jeden bajt, więc używaj go tylko wtedy, gdy chcesz natychmiast uzyskać dostęp do ostatniego elementu w tym samym czasie.A[k=1:end], w którym to przypadku kzachowa iterator pasujący1:length(A) . Może to być przydatne, gdy chcesz jednocześnie korzystać z tablicy A.collect(A), użyj[A...] , który zrobi to samo i pozwoli zaoszczędzić 4 bajty."$(s[i])"lubdec(s[i]) do wyrażeń lub zmiennych wieloznakowych oraz "$i"do zmiennych jednoznakowych.?:zamiast &&lub ||do przypisania warunkowego - to znaczy, jeśli chcesz wykonać przypisanie tylko pod pewnymi warunkami, możesz zapisać jeden bajt, pisząc cond?A=B:1zamiast cond&&(A=B), cond?1:A=Ba niecond||(A=B) . Zauważ, że 1tutaj jest to wartość pozorna.unionlub ∪zamiastunique - union(s)zrobi to samo co unique(s)i zapisze bajt w tym procesie. Jeśli możesz użyć znaków spoza ASCII, ∪(s)zrobisz to samo i ∪kosztuje tylko 3 bajty zamiast 5 bajtów w union.split("Hi there")ponieważ argument wzorca domyślnie jest spacją.
Przedefiniowanie operatorów pozwala zaoszczędzić wiele bajtów w nawiasach i przecinkach.
Aby uzyskać jedyny przykład, porównaj następujące rekurencyjne implementacje sekwencji Fibonacciego:
F(n)=n>1?F(n-1)+F(n-2):n # 24 bytes
!n=n>1?!~-n+!(n-2):n # 20 bytes
!n=n>1?!~-n+!~-~-n:n # 20 bytes
Przedefiniowany operator zachowuje swój pierwotny priorytet.
Zauważ, że nie mogliśmy po prostu zamienić się !na ~, ponieważ ~jest już zdefiniowany dla liczb całkowitych, podczas gdy !jest zdefiniowany tylko dla boolean.
Nawet bez rekurencji ponowne zdefiniowanie operatora jest krótsze niż zdefiniowanie funkcji binarnej. Porównaj następujące definicje prostego testu podzielności.
f(x,y)=x==0?y==0:y%x==0 # 23 bytes
(x,y)->x==0?y==0:y%x==0 # 23 bytes
x->y->x==0?y==0:y%x==0 # 22 bytes
x\y=x==0?y==0:y%x==0 # 20 bytes
Poniżej przedstawiono sposób przedefiniowania operatora binarnego w celu obliczenia funkcji Ackermann:
A(m,n)=m>0?A(m-1,n<1||A(m,n-1)):n+1 # 35 bytes
^ =(m,n)->m>0?(m-1)^(n<1||m^~-n):n+1 # 36 bytes
| =(m,n)->m>0?m-1|(n<1||m|~-n):n+1 # 34 bytes
m\n=m>0?~-m\(n<1||m\~-n):n+1 # 28 bytes
Pamiętaj, że ^jest to nawet dłużej niż zwykły identyfikator, ponieważ jego priorytet jest zbyt wysoki.
Jak wspomniano wcześniej
m|n=m>0?m-1|(n<1||m|~-n):n+1 # 28 bytes
nie działałby dla argumentów liczb całkowitych, ponieważ |w tym przypadku jest już zdefiniowany. Definicję liczb całkowitych można zmienić za pomocą
m::Int|n::Int=m>0?m-1|(n<1||m|~-n):n+1 # 38 bytes
ale to zbyt długo. Jednak to robi pracę, jeśli mijamy pływaka jako argumentu lewej i prawej całkowitą jako argumentu.
Nie daj się łatwo uwieść czynnikowi (n) Kusząca funkcja biblioteki podstawowej factor(n)ma fatalną wadę: zwraca faktoryzację liczby całkowitej w nieuporządkowanym Dicttypie. W związku z tym wymaga kosztownych collect(keys())i collect(values())potencjalnie także a cati a, sortaby uzyskać potrzebne dane. W wielu przypadkach taniej jest po prostu wziąć pod uwagę podział prób. Smutne ale prawdziwe.
Użyj mapy map to świetna alternatywa dla zapętlania. Zdawać sobie sprawę z różnicy pomiędzy mapa map!i wykorzystać funkcjonalność ta ostatnia, kiedy można w miejscu.
Zastosowanie mapreduce mapreduce jeszcze bardziej rozszerza funkcjonalność mapy i może być znaczącym oszczędzaniem bajtów.
Anonimowe funkcje są świetne! .. szczególnie, gdy przejdziemy do wyżej wymienionych mapfunkcji.
Funkcje skumulowanej tablicy cumprod , cumsumaromatyczne cummini inne podobnie nazwane funkcje umożliwiają kumulatywne operacje wzdłuż określonego wymiaru n-wymiarowej tablicy. (Lub * un * określono, jeśli tablica ma wartość 1-d)
Krótka notacja dla Any Jeśli chcesz wybrać cały konkretny wymiar tablicy wielowymiarowej (lub Dict), np. A[Any,2]Możesz zapisać bajty za pomocąA[:,2]
Użyj funkcji jednowierszowej dla funkcji Zamiast tego function f(x) begin ... endczęsto możesz uprościćf(x)=(...)
Użyj operatora trójskładnikowego Może to być oszczędność miejsca dla konstrukcji z wyrażeniem pojedynczym wyrażenia If-Then-Else. Ostrzeżenia: Chociaż w niektórych innych językach jest to możliwe, nie można pominąć części po dwukropku w Julii. Ponadto operator ma poziom wyrażeń w Julii, więc nie można go używać do warunkowego wykonywania całych bloków kodu.
if x<10 then true else false endvs
x<10?true:false
Jest to również możliwe w innych językach, ale zwykle dłużej niż prosta metoda. Jednak zdolność Julii do redefiniowania jej jednoargumentowych i binarnych operatorów sprawia, że gra jest dość golfowa.
Na przykład, aby wygenerować tabelę dodawania, odejmowania, mnożenia i dzielenia dla liczb naturalnych od 1 do 10, można użyć
[x|y for x=1:10,y=1:10,| =(+,-,*,÷)]
który redefines binarnego operatora |jak +, -, *i ÷, następnie oblicza x|ydla każdej operacji, a xi yw pożądanych granicach.
Działa to również dla jednoargumentowych operatorów. Na przykład, aby obliczyć liczby zespolone 1 + 2i , 3-4i , -5 + 6i i -7-8i , ich negatywy, ich złożone koniugaty i ich multiplikatywne inwersje, można użyć
[~x for~=(+,-,conj,inv),x=(1+2im,3-4im,-5+6im,-7-8im)]
który redefines jednoargumentowy operatora ~jak +, -, conji inv, następnie oblicza ~xdla wszystkich żądanych liczb zespolonych.
Sekwencje żeńskie i męskie (binarne)
Permutacja sprawy (jednostkowa)
Słowa kluczowe mogą czasami natychmiast następować po stałych bez potrzeby stosowania spacji lub średnika. Na przykład:
n->(for i=1:n n-=1end;n)
Zwróć uwagę na brak spacji między 1i end. Dotyczy to również zjawiska endwystępującego po zamknięciu miąższu, tj )end.
Wykonać Integer podział stosując ÷zamiast div()lub przeciążenia operatora. Zauważ, że ÷w UTF-8 jest wart 2 bajty.
Użyj vec()lub A[:](dla niektórych tablic A) zamiast, reshape()gdy to możliwe.
Twórz funkcje zamiast pełnych programów, jeśli jest to dozwolone w regułach wyzwania. Krótsze jest zdefiniowanie funkcji, która akceptuje dane wejściowe niż definiowanie zmiennych poprzez odczyt ze standardowego wejścia. Na przykład:
n->(n^2-1)
n=read(STDIN,Int);n^2-1Zmienne można zwiększać wewnątrz argumentu funkcji. Na przykład, oto moja odpowiedź na wyzwanie Znajdź następny 1-rzadki numer binarny :
n->(while contains(bin(n+=1),"11")end;n)
Jest to krótsze niż zwiększanie nwewnątrz pętli.
Wprowadzono w Julii 0.5. To jest jak mapa, ale zużywa mniej znaków i zachowuje się w stosunku do swoich argumentów - co oznacza, że możesz napisać mniej lambda do radzenia sobie z rzeczami.
Zamiast:
map(f,x) - 8 znaków.f.(x) - 5 znakówJeszcze lepiej:
map(a->g(a,y),x) - 16 znakówg.(x,[y]) - 9 znaków