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\b
zamiast 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"^a
do 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 a
i 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 x
będą miały co najmniej dwa elementy. Alternatywnie, jeśli wiesz, że wszystkie elementy x
bę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]]
.end
indeksowania 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 k
zachowa 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:1
zamiast cond&&(A=B)
, cond?1:A=B
a niecond||(A=B)
. Zauważ, że 1
tutaj jest to wartość pozorna.union
lub ∪
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 Dict
typie. W związku z tym wymaga kosztownych collect(keys())
i collect(values())
potencjalnie także a cat
i a, sort
aby 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 map
a 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 map
funkcji.
Funkcje skumulowanej tablicy cumprod
, cumsum
aromatyczne cummin
i 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 ... end
czę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 end
vs
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|y
dla każdej operacji, a x
i y
w 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 +
, -
, conj
i inv
, następnie oblicza ~x
dla 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 1
i end
. Dotyczy to również zjawiska end
wystę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-1
Zmienne 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 n
wewną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