Jakie masz ogólne wskazówki na temat gry w golfa w Mathematica? Szukam pomysłów, które można by zastosować do problemów z golfem w kodzie, które są przynajmniej nieco specyficzne dla Mathematica (np. „Usuń komentarze” nie jest odpowiedzią).
Poniższe wskazówki różnią się od najbardziej ekonomicznych do najczęściej używanych:
Jeśli to możliwe, używaj poleceń wysokiego poziomu Mathematiki, nawet nieporęcznych:
MorphologicalComponents
: Code-Golf: Count Islands
Możliwości manipulacji obrazem: np. Dzisiaj (24 września) są urodziny HONDA
Subsets
IntegerPartitions
Miary odległości i podobieństwa: np. EuclideanDistance
Mogą być oszczędzaniem bajtów. Zauważ jednak, że zwykle krótsze jest pisanie Total@Abs[a-b]
zamiast a~ManhattanDistance~b
i Max@Abs[a-b]
zamiast a~ChessboardDistance~b
.
Użyj Graphics and
Text
do sztuki Ascii: np. Programowanie gwiazd!
i zbuduj zegar analogowy
Dedykowane symbole:
logiczne i ustawiaj symbole operacji zamiast ich długich nazw postaci: ⋂, ⋃, ∧, ∨
Map
i Apply
: /@
, //@
. @@
,@@@
Notacja przedrostka i przyrostka:
Print@"hello"
zamiast Print["hello"]
a~f~b
zamiast f[a,b]
Gdy funkcja jest używana tylko raz, czysta funkcja może oszczędzić jeden lub dwa znaki.
Łączenie ciągów na liście. ""<>{"a","b","c"}
zamiastStringJoin@{"a","b","c"}
Wykorzystaj funkcje z listą. Im dłuższe listy, tym lepiej.
{a, b, c} + {x, y, z}= {a+x, b+y, c+z}
{2, 3, 4} {5, 6, 7}= {10, 18, 28}
{{a, b}, {c, d}}^{2, 3} = {{a^2, b^2}, {c^3, d^3}}
(Norm[#-#2]&)
niżEuclideanDistance
.Niektóre wbudowane funkcje o długich nazwach można zastąpić krótszymi wyrażeniami.
Na przykład:
Total
=>Tr
Transpose
=>Thread
lub\[Transpose]
True
=>1<2
False
=>1>2
Times
=>1##&
Alternatives
=>$|##&
IntegerQ
=>⌊#⌋==#&
a[[1]]
=>#&@@a
a[[All,1]]
=>#&@@@a
ConstantArray[a,n]
=>Array[a&,n]
lubTable[a,{n}]
Union@a
=>{}⋃a
luba⋃a
ToExpression@n
=>FromDigits@n
jeślin
jest liczbąDivisible[n,m]
=>m∣n
FromDigits[n,2]
=>Fold[#+##&,n]
ifn
jest listą0
s i1
sComplex@z
=>{1,I}.z
gdziez
jest lista formularza{x,y}
źródło
Thread[{{a,b},{c,d}}]
==Thread[List[{a,b},{c,d}]]
=={List[a,c],List[b,d]}
=={{a,c},{b,d}}
==Transpose[{{a,b},{c,d}}]
Fold
sztuczkaFromDigits
działa również na każdą inną bazę oprócz10
. Np.FromDigits[n,5]
->Fold[4#+##&,n]
(z premią za zaoszczędzenie dodatkowego bajtu dla baz100
i1000
).U+F3C7
.Echo
jest to opcja, ponieważ drukuje>>
(i spację) na STDOUT przed wydrukowaniem rzeczywistego ciągu.Complex[x,y] => {1,I}.{x,y}
myślę, żex+y*I
jest znacznie krótszy z tym samym efektem?Listy z powtarzanymi wartościami
Jest to dość powszechny wektor do pracy z:
Okazuje się, że można to skrócić bajtem:
Nawet więcej bajtów jest zapisywanych, jeśli wektor jest dłuższy niż dwa zera. Można to również wykorzystać do zainicjowania macierzy zerowych, np. Poniższe daje macierz 2x2 zer:
Można to również zastosować do wartości niezerowych, jeśli są one wystarczająco duże, wystarczająco liczne lub ujemne. Porównaj następujące pary:
Pamiętaj jednak, że od 6 wartości lepiej jest
1~Table~6
w tym przypadku (potencjalnie wcześniej, w zależności od wymagań pierwszeństwa).Powodem tego jest to, że
,
wprowadza dwa argumenty na listę, ale argumenty pominięte (gdziekolwiek w Mathematica) są niejawneNull
. Co więcej, mnożenie jestListable
i0*x
jest0
do prawie każdegox
(z wyjątkiem rzeczy takich jakInfinity
iIndeterminate
), więc oto co się dzieje:W przypadku list
1
s można użyć podobnej sztuczki, korzystając z reguł potęgowania. Istnieją dwa różne sposoby zapisywania bajtów, jeśli1
na liście są co najmniej trzy s:źródło
1^{,,,}
jest o jeden bajt mniejszy niż0{,,,}+1
.{,,}^0
. Zmienię post.Poznaj swoje argumenty funkcji czystej
Podczas gry w golfa często stosujesz podejście funkcjonalne, w którym używasz anonimowych (czystych) funkcji ze
&
składnią stenografii. Istnieje wiele różnych sposobów na uzyskanie dostępu do argumentów takiej funkcji, i często można ogolić kilka bajtów, dobrze znając możliwości.Dostęp do pojedynczych argumentów
Prawdopodobnie wiesz o tym, jeśli wcześniej używałeś czystych funkcji. N p argument dalej
#n
, i#
działa jako aliasu#1
. Jeśli więc powiedzmy, że chcesz napisać funkcję, która przyjmuje jako parametry inną funkcję i jej argument (aby przekazać argument do tej funkcji), użyjNie działa to z liczbami ujemnymi (takimi jak możesz użyć podczas uzyskiwania dostępu do list).
Dostęp do nazwanych argumentów (nowość w V10)
Jedną z głównych nowych funkcji językowych w Mathematica 10 są
Association
s, które są w zasadzie mapami klucz-wartość z dowolnymi typami kluczy, napisanymi jakJeśli takie powiązanie zostanie przekazane jako pierwszy argument do funkcji czystej, możesz uzyskać dostęp do niektórych, jeśli jej argumenty są nazwanymi parametrami:
Zauważ, że
#
nadal odnosi się do całego powiązania, zgodnie z oczekiwaniami. Aby nazwane parametry działały, klucze muszą być ciągami (nie będzie działać, jeśli użyjesz na przykład niezdefiniowanych zmiennych), a ciągi te muszą zaczynać się od litery i zawierać tylko litery i cyfry.Argument „ja”
#0
Istnieje mniej znana funkcja, która
#0
również istnieje i daje sam obiekt funkcji. Może to być bardzo przydatne w quinach i quinach uogólnionych. W rzeczywistości najkrótsza quine Mathematica (o której wiem) toNieco denerwujące jest to, że nie da ci dokładnie tych znaków, które wprowadziłeś. Np. Jeśli użyjesz
@
aplikacji funkcji, nadal będzie renderować jako,[...]
a spacje zostaną wstawione w niektórych miejscach. Zwykle spowoduje to, że quine będzie trochę dłuższa, niż byś chciał, ale zawsze będzie działać, najpierw grając w golfa, a następnie kopiując jego wynik - co powinno być teraz prawdziwym quine.Oprócz quinesów oznacza to również, że możesz pisać kod rekurencyjny bez konieczności nazywania swojej funkcji. Porównaj te trzy (naiwne, ale gra w golfa) implementacje Fibonacciego:
Sekwencje argumentów
Teraz zaczyna się prawdziwa magia. Sekwencje nie są często używane w golfie, ponieważ nazwa
Sequence
jest zbyt długa, aby przez większość czasu była tego warta. Ale w czystych funkcjach świecą. Jeśli nie jesteś zaznajomiony z sekwencjami, są one w zasadzie jak ikony w innych językach, jeśli użyjesz sekwencjiList
na liście argumentów funkcji lub, jej elementy zostaną automatycznie rozwinięte w osobne miejsca. WięcTeraz w czystych funkcjach
##
lub##1
jest sekwencją wszystkich argumentów. Podobnie##2
jest sekwencją wszystkich argumentów rozpoczynających się od drugiego,##3
wszystkich argumentów rozpoczynających się od trzeciego itd. Tak więc na początek możemy po prostu zaimplementowaćSequence
jako##&
, oszczędzając 5 bajtów. Jako przykładowe użycie daje nam to alternatywę dlaJoin@@list
(zobacz tę wskazówkę ), która nie zapisuje żadnych bajtów, ale i tak warto o tym wiedzieć:To skutecznie spłaszcza pierwszy poziom zagnieżdżonej listy. Co jeszcze możemy z tym zrobić? Oto 2 bajty krótsza alternatywa dla
RotateLeft
:W przypadku tych samych rzeczy warto pamiętać o tej funkcji. Możemy jednak zrobić lepiej! Sekwencje stają się naprawdę interesujące, gdy weźmiemy pod uwagę, że operatory są faktycznie realizowane jako funkcje pod maską. Np.
a+b
Faktycznie ocenia naPlus[a,b]
. Więc jeśli podamy tę sekwencję ...Ta sztuczka została użyta w tym poradniku, aby zaoszczędzić bajt
Times
, ponieważ zestawienie jest technicznie także tylko operatorem:Możesz go również użyć do zapisania bajtu,
Unequal
jeśli masz wartość jednoznakową lub zmienną, o której wiesz, że nie ma jej w argumentach (N
prawdopodobnie zadziała w 99% przypadków):Staje się to jeszcze bardziej interesujące w przypadku operatorów jednoargumentowych
-
i/
- te dwa ostatnie są faktycznie realizowane pod względem mnożenia i potęgowania. Oto lista rzeczy, które możesz zrobić, gdzie w ostatniej kolumnie założono, że funkcja przekazała argumentya, b, c
:Inne częste operatorzy
!=
,==
,&&
,||
. Mniej spotykane, aby pamiętać to|
,@*
,/*
. Podsumowując, oto mała sztuczka bonusowa:Eksperymentuj z nimi i daj mi znać, jeśli znajdziesz jakieś inne przydatne lub szczególnie interesujące aplikacje!
źródło
Sqrt@2
lub2^.5
=>√2
a[[1]]
=>a〚1〛
#+#2&
=>+##&
Flatten@a
=>Join@@a
(czasami)Function[x,x^2]
=>xx^2
lub#^2&
a〚1;;-1;;2〛
=>a〚;;;;2〛
a〚2;;-1 ;;2〛
=>a〚2;;;;2〛
a〚All,1〛
=>a〚;;,1〛
{{1}}〚1,1〛
=>Tr@{{1}}
0&~Array~10
=>0Range@10
Range[10^3]
=>Range@1*^3
źródło
〚
i〛
zajmuje 3 bajty każda (zakładamy UTF8)Operatory jako funkcje
Zainspirowany niedawnym odkryciem Dennisa dla Julii , pomyślałem, że przyjrzę się Mathematice. Wiedziałem, że Mathematica definiuje dużą liczbę nieużywanych operatorów, ale nigdy nie zwracałem na to większej uwagi.
W celach informacyjnych listę wszystkich operatorów można znaleźć tutaj w formie tabeli pierwszeństwa. Trójkąt w ostatniej kolumnie wskazuje, czy ten operator ma wbudowane znaczenie, czy nie. Chociaż nie wszystkie z nich, których nie można łatwo zdefiniować, większość z nich.
Dogodnie są dwa nieużywane operatory o punkcie kodowym mniejszym niż 256, tak że można ich używać jako pojedynczych bajtów w pliku źródłowym zakodowanym w standardzie ISO 8859-1:
±
(0xB1) może być używany zarówno jako operator jednoargumentowy, jak i operator binarny.·
(0xB7) może być użyte jako operator wariacyjny lub n-arylowy, dla n> 2.Jest jeszcze jeden haczyk: z jakiegoś dziwnego powodu przy definiowaniu tych operatorów potrzebujesz przed nimi jednego miejsca, bo inaczej Mathematica spróbuje parsować mnożenie. Podczas ich używania nie potrzebujesz jednak żadnych spacji:
Porównaj to z:
To oszczędza jeden bajt podczas definiowania funkcji i dwa bajty podczas jej używania. Zauważ, że definicja
·
nie zapisuje bajtów dla czterech argumentów i zacznie kosztować bajty dla większej liczby argumentów, ale użycie może nadal oszczędzać bajty, w zależności od priorytetu operatorów używanych w argumentach. Warto również zauważyć, że można tanio zdefiniować funkcję wariadyczną, którą można następnie wywołać znacznie wydajniej:Należy jednak pamiętać, że wywołanie tych funkcji variadycznych przy pomocy jednego argumentu nie jest łatwe. (Można to zrobić
CenterDot[x]
lub##&[]·x
jeśli jednak trzeba, że istnieje duża szansa, że jesteś lepiej z innego rozwiązania.)Oczywiście nie zapisuje to niczego dla rozwiązań, w których wystarczy funkcja bez nazwy, ale czasami trzeba zdefiniować funkcje pomocnicze do późniejszego użycia, a czasem krótsze jest zdefiniowanie nazwanych funkcji, np. W celu ustawienia różnych definicji dla różnych parametrów. W takich przypadkach użycie operatora może zaoszczędzić przyzwoitą liczbę bajtów.
Pamiętaj, że korzystanie z tych plików zakodowanych w standardzie ISO 8859-1 wymaga
$CharacterEncoding
ustawienia zgodnej wartości, takiej jak wartość domyślna systemu WindowsWindowsANSI
. W niektórych systemach domyślnieUTF-8
nie będzie w stanie odczytać tych punktów kodu z pojedynczych bajtów.źródło
Wybieranie wartości na podstawie liczby całkowitej
Naiwne podejście do wyboru pomiędzy
y
iz
, w zależności od tego, czyx
jest,0
czy1
jestIstnieje jednak krótsza droga:
To działa, ponieważ
[[0]]
dajeHead
wyrażenia, w tym przypadkuy
, podczas gdy[[1]]
po prostu daje pierwszy element - w tym przypadku pierwszego argumentuz
.Możesz nawet użyć tego, aby wybrać pomiędzy więcej niż dwiema wartościami:
Zauważ, że to nie zadziała, jeśli
u
jest to funkcja, która faktycznie coś ocenia. Ważne jest, aby Mathematica zachowału[v,w]
taki, jaki jest. Działa to jednak w większości przypadków, w tym jeśliu
a jest liczbą, łańcuchem lub listą.Kredyty za tę sztuczkę trafiają do alephalpha - odkryłem to w jednej z jego odpowiedzi.
Jeśli
x
jest oparty na 1 zamiast na zero, po prostu użyjlub
W niektórych rzadkich przypadkach możesz nawet skorzystać z faktu, że mnożenie nie jest oceniane dla niektórych wartości:
Zauważ jednak, że Mathematica faktycznie zmieni kolejność argumentów mnożenia, jeśli pozostanie nieocenione, więc powyższe jest identyczne z
źródło
Alternatywy dla
Length
Zostało to całkowicie przepisane z kilkoma sugestiami LegionMammal978 i Miszy Ławrow. Wielkie dzięki dla obu z nich.
W wielu przypadkach
Length
można go nieco skrócić, korzystając zTr
. Podstawową ideą jest przekształcenie danych wejściowych w listę1
s, tak żeTr
sumuje się je, co równa się długości listy.Najczęstszym sposobem na to jest użycie
1^x
(dla listyx
). DziałaPower
to, ponieważ jestListable
i1^n
dla większości wartości atomowychn
jest po prostu1
(w tym wszystkie liczby, łańcuchy i symbole). Dzięki temu możemy już zapisać jeden bajt:Oczywiście zakłada się, że
x
jest to wyrażenie o wyższym priorytecie niż^
.Jeśli
x
zawiera tylko0
si1
, możemy zapisać kolejny bajt przy użyciuFactorial
(zakładając, żex
ma wyższy priorytet niż!
):W niektórych rzadkich przypadkach
x
może mieć niższy^
priorytet niż mnożenie. W takim przypadku będzie mieć również niższy priorytet niż@
, więc naprawdę musimy to porównaćLength[x]
. Przykładem takiego operatora jest.
. W takich przypadkach nadal można zapisać bajt za pomocą tego formularza:Na koniec kilka uwag na temat rodzaju list, na których to działa:
Jak wspomniano na górze, działa to na płaskich listach zawierających tylko liczby, ciągi znaków i symbole. Będzie jednak działał również na niektórych głębszych listach, chociaż w rzeczywistości oblicza coś nieco innego. W przypadku n -D tablicy prostokątnej, użycie
Tr
daje najkrótszy wymiar (w przeciwieństwie do pierwszego). Jeśli wiesz, że najbardziej zewnętrzny wymiar jest najkrótszy lub wiesz, że wszystkie są takie same, toTr
-wyrażenia są nadal równoważneLength
.źródło
Length@x == Tr[1^x]
. Powinien działać z większością list.Tr[x!]
zamiastTr[1^x]
zapisywać jeden bajt w specjalnym przypadku, w którymx
zawiera tylko zera i jedynki.Poznaj rozwiązania rekurencyjne - Mathematica to paradygmat, ale podejście funkcjonalne jest często najbardziej ekonomiczne.
NestWhile
może być bardzo zwartym rozwiązaniem problemów z wyszukiwaniemNestWhileList
iFoldList
ma dużą moc, gdy trzeba zwrócić lub przetworzyć wyniki pośrednich iteracji.Map (/@)
,Apply (@@, @@@)
,MapThread
, I naprawdę wszystko na Wolframa Functional Programming stronie dokumentacji jest silnym rzeczy.Skrócona forma inkrementacji / dekrementacji - Na przykład zamiast tego
While[i<1,*code*;i++]
możesz zrobićWhile[i++<1,*code*]
Nie zapomnij, że możesz wstępnie zwiększyć / zmniejszyć - na przykład
--i
zamiasti--
. Może to czasem zaoszczędzić kilka bajtów w otaczającym kodzie, eliminując operację przygotowawczą.W następstwie nr 5 Davida Carrahera: Gdy ta sama funkcja jest używana wiele razy, przypisanie jej symbolu może zaoszczędzić bajty. Na przykład, jeśli używasz
ToExpression
4 razy w roztworze,t=ToExpression
umożliwiat@*expression*
późniejsze użycie . Jednak zanim to zrobisz, zastanów się, czy wielokrotne stosowanie tej samej funkcji wskazuje na możliwość bardziej ekonomicznego podejścia rekurencyjnego.źródło
MapThread
często można zastąpić\[Transpose]
. TIO .Nie używaj,
{}
jeśli używasz@@@
.W niektórych przypadkach możesz napotkać wyrażenie takie jak:
Można zmniejszyć bajty pisząc:
Alternatives
ma bardzo niski priorytet, więc generalnie dobrze jest pisać wyrażenia (zauważalnym wyjątkiem są czyste funkcje; możesz używać go tylko w lewym skrajnym elemencieAlternatives
).Zauważ, że
f@@a|b|c
(zamiastf@@{a,b,c}
) nie działa, ponieważApply
ma wyższy priorytet niżAlternative
.W takim przypadku powinieneś po prostu użyć
f@@{a,b,c}
.źródło
Tylko Mathematica 10
Formularze operatora
Mathematica 10 obsługuje tak zwane „formy operatora”, co w zasadzie oznacza, że niektóre funkcje mogą być obsługiwane. Currywanie funkcji polega na utworzeniu nowej funkcji przez naprawienie jednego z jej operatorów. Powiedz, że używasz
SortBy[list, somereallylongfunction&]
wielu różnychlist
s. Przed, prawdopodobnie byłby przypisanySortBy
dos
i czysta funkcja dof
zarzutówTeraz możesz curry
SortBy
, co oznacza, że możesz to zrobićTe same prace dla wielu innych funkcji, które biorą listy lub argumentu funkcji, w tym (ale nie tylko)
Select
,Map
,Nearest
, itd.ybeltukov na Mathematica.SE był w stanie stworzyć pełną listę :
Skład i prawy skład
Istnieją nowe skróty dla
Composition
(@*
) iRightComposition
(/*
). Oczywiście wymyślony przykład, w którym mogą one zapisywać znaki, znajduje się w następujących trzech równoważnych wierszachźródło
Nie pisz funkcji 0-argumentowych
Nie ma potrzeby takiego kodu:
Możesz po prostu użyć zmiennej,
:=
aby wymusić ponowną ocenę prawej strony:Oznacza to również, że możesz aliasować dowolną często wykonywaną akcję (nawet jeśli jest to coś podobnego
n++
) do jednego znaku, kosztem 5 bajtów. W takim przypadkun++
zwraca się po czwartym użyciu:źródło
Użyj,
%
aby uzyskać darmową zmiennąTa wskazówka ma zastosowanie tylko wtedy, gdy można założyć środowisko REPL Mathematica.
%
nie jest zdefiniowany, gdy kod jest uruchamiany jako skrypt.Kiedy można skorzystać z funkcji rEPL, nie rób tego:
Zamiast tego pamiętaj, że Mathematica przechowuje ostatnio ocenione wyrażenie (zakończone znakiem nowej linii) w
%
:Dodana nowa linia kosztuje bajt, ale oszczędzasz dwa, usuwając
a=
, więc ogólnie oszczędza to jeden bajt.W niektórych przypadkach (np. Gdy i tak chcesz wydrukować wartość
a
), możesz nawet pominąć;
, oszczędzając dwa bajty:Jeden lub dwa bajty mogą wydawać się dość niewielkie, ale jest to ważny przypadek, ponieważ sprawia, że ekstrakcja powtarzających się wyrażeń (co jest bardzo powszechną techniką) jest znacznie bardziej przydatna podczas gry w golfa:
Normalna technika wyodrębniania powtarzanych wyrażeń kosztuje cztery bajty narzutu, które należy zapisać przez dalsze użycie wyrażenia. Oto krótka tabela minimalnej liczby zastosowań wyrażenia (według długości wyrażenia) do wyodrębnienia do nazwanej zmiennej w celu zapisania czegokolwiek:
Przy użyciu zmiennej bez nazwy możliwe będzie znacznie częstsze zapisywanie kilku bajtów:
Nie sądzę
%%
ani nie%n
można go użyć do gry w golfa, ponieważ jeśli nie użyjesz ich co najmniej dwa razy, możesz po prostu umieścić wyrażenie dokładnie tam, gdzie jest potrzebne. A jeśli użyjesz go dwa razy, dodatkowy znak w nazwie zmiennej anuluje oszczędności wynikające z pominięcia niektórychx=
.źródło
Sprawdzanie, czy lista jest posortowana
Jest to zasadniczo następstwo tej wskazówki, ale jest to wystarczająco powszechne zadanie, które moim zdaniem uzasadnia własną odpowiedź.
Naiwnym sposobem sprawdzenia, czy lista jest w porządku, jest użycie
Możemy zrobić jeden bajt lepiej
Nie działa to jednak, jeśli nie mamy już tego, co chcielibyśmy sprawdzić w zmiennej. (Potrzebowalibyśmy czegoś,
Sort[a=...]==a
co jest niepotrzebnie długie.) Istnieje jednak inna opcja:Najlepszą rzeczą jest to, że można to wykorzystać do sprawdzenia, czy dane wejściowe są sortowane odwrotnie dla tej samej liczby bajtów:
Kolejny bajt można zapisać, jeśli a) wiemy, że elementy listy są różne ib) znamy dolną granicę między 0 a 9 (włącznie; lub górną granicę dla odwrotnego porządku sortowania):
Aby zobaczyć, dlaczego to działa, sprawdź „Sekwencje argumentów” we wskazówce znajdującej się u góry.
źródło
##>0&@@a
. Podobne dla górnej granicy sortowania.Powtarzanie łańcucha
Zamiast
StringRepeat[str,n]
używać(0Range[n]+str)<>""
. Lub jeślistr
nie zależy od argumentów dotyczących slotów, jeszcze lepiej jestArray[str&,n]<>""
według tej wskazówki.źródło
StringRepeat[s,n+1]
używaćArray[s&,n]<>s
(nawet jeśli masz jużn+1
zmienną).Table[str,n]<>""
Jeśli potrzebujesz listy liczb posortowanych odwrotnie, nie używaj
ale
aby zapisać sześć bajtów. Sortowanie według wartości ujemnej jest również przydatne w
SortBy
scenariuszach:źródło
-Sort@-x
?Możesz wstawić wyrażenie, w
Break
którym można zapisać jeden lub dwa znaki. Przykład ( inne szczegóły nie dla golfa dla jasności ):można zamienić
aby uratować jedną postać. Jeśli dane wyrażenie nie ma niższego priorytetu niż aplikacja funkcji, możesz nawet zapisać inny znak:
można zamienić
Chociaż nieudokumentowany, argument, który
Break
wydaje się być zwracany przez otaczającą pętlę, może potencjalnie prowadzić do jeszcze większej oszczędności.źródło
Aby usunąć wszystkie białe znaki z ciągu
s
, użyjTo znaczy użyj
StringSplit
domyślnego (podzielonego na komponenty niebiałe) i po prostu połącz je z powrotem. To samo jest prawdopodobnie najkrótsze, jeśli chcesz pozbyć się jakiejkolwiek innej postaci lub podłańcucha:źródło
Alternatywy dla
Range
Bardzo częstym zadaniem jest zastosowanie jakiejś funkcji do wszystkich liczb od 1 do a
n
(zwykle podawanych jako dane wejściowe). Istnieją zasadniczo 3 sposoby, aby to zrobić (na przykład używając nienazwanej funkcji tożsamości):Zwykle wybieram pierwszy (z jakiegokolwiek powodu), ale rzadko jest to najlepszy wybór.
Używanie
Array
zamiast tegoPowyższy przykład pokazuje, że użycie
Array
ma tę samą liczbę bajtów. Ma jednak tę zaletę, że jest pojedynczym wyrażeniem. W szczególności, jeśli chcesz dalej przetwarzać wynik za pomocą funkcjif
, możesz użyć notacji przedrostkowej, co oszczędza bajtRange
:Ponadto możesz ominąć nawiasy wokół funkcji bez nazwy, których możesz potrzebować
Range
npJeśli nie chcesz go dalej używać (lub z operatorem, który ma mniejszy priorytet), możesz zamiast tego napisać
Array
się w notacji infiksowej, a także zapisać bajt:Dlatego
Array
prawie na pewno jest lepszy niżRange
.Używanie
Table
zamiast tegoTeraz tabela musi składać się z 3 bajtów lub co najmniej 2, gdy zapis infix jest opcją:
Gdy nie używasz notacji infix,
Table
możesz pominąć nawiasy, jeśli twoja funkcja składa się z kilku instrukcji:Jest to jeszcze dłuższe, ale daje dodatkowe oszczędności w przypadku wymienionym poniżej.
Rzeczywiste oszczędności wynikają z faktu, że
Table
nazwa działającej zmiennej nie powinna zostać odrzucona. Często zagnieżdżasz funkcje bez nazw, w których chcesz użyć zmiennej zewnętrznej w jednej z funkcji wewnętrznych. Kiedy tak się dzieje,Table
jest krótszy niżRange
:Zapisujesz nie tylko znaki do przypisania
i
, ale możesz również zredukować funkcję do pojedynczej instrukcji w tym procesie, co pozwoli ci na użycie notacji infix. Dla porównania,Array
w tym przypadku jest również dłuższy, ale wciąż krótszy niżRange
:Kiedy faktycznie używałbyś
Range
?Ilekroć nie potrzebujesz wywołania funkcji do przetworzenia wartości, np. Kiedy mapowanie można wykonać za pomocą operacji wektorowej. Na przykład:
Oczywiście jest również krótszy, jeśli nie chcesz mapować żadnej funkcji, np
źródło
f/@Range[x]
regularnie używa ...Znalezienie najmniejszej liczby spełniającej warunek
Niektóre podobne konstrukcje
i=1;While[cond[i],i++]
są w porządku, ale istnieje alternatywa, która jest o dwa bajty krótsza:Powyższy kod wielokrotnie zastępuje szereg
i
zei+1
podczas gdy spełnia warunekcond[i]
. W takim przypadkui
zaczyna się od1
.Zauważ, że domyślna maksymalna liczba iteracji wynosi 2 ^ 16 (= 65536). Jeśli potrzebujesz więcej iteracji,
While
byłoby lepiej. (MaxIterations->∞
jest za długi)źródło
Ocena zwarcia nadużycia
Czasami możesz zastąpić
If
operatorem logicznym.Załóżmy na przykład, że chcesz utworzyć funkcję, która sprawdza, czy liczba jest liczbą pierwszą, a wypisuje,
2*(number) - 1
jeśli to prawda:Jest krótszy, jeśli użyjesz
&&
zamiast tego:Nawet jeśli masz wiele wyrażeń, nadal zapisujesz bajty:
Możesz użyć
||
w przypadkach, gdy chcesz, aby warunek byłFalse
:Te sztuczki działają, ponieważ operatory logiczne mogą być zwarte ; drugi argument, a następnie nie muszą nawet być prawidłowymi wyrażeniami logicznymi.
Oczywiście nie działa to, jeśli potrzebujesz wartości zwracanej
If
lub gdy potrzebujesz zarówno prawdziwych, jak i fałszywych argumentówIf
.źródło
Oto lista z mnóstwem formularzy wejściowych operatora, które mogą skrócić wiele rzeczy. Niektóre z nich zostały wymienione w innych postach, ale lista jest długa i zawsze jestem zaskoczony, gdy znalazłem tam kilka nowych rzeczy:
źródło
Za pomocą
Optional (:)
Optional (:)
może służyć do rozwijania list w zamianach, bez konieczności definiowania osobnej reguły dla rozwinięcia.Ta odpowiedź przeze mnie i ta odpowiedź @ngenisis są przykładami.
Stosowanie
Powyższa zamiana najpierw wykorzystuje wzorzec
{p___, a_, b_, q___}
i znajduje takie dopasowanie, któreb
spełnia określony warunek.Gdy nie znaleziono takiego dopasowania, pomija
a_
i zamiast tego szuka{p___, b_, q___}
.a
nie jest uwzględniany podczas wyszukiwania i zakłada się, że ma wartość0
.Zauważ, że drugie wyszukiwanie wzorca działałoby tylko dla
b
tego, które występuje na początku listy; jeślib
wartość spełniająca warunek znajduje się pośrodku, wówczas{p___, a_, b_, q___}
(która ma wyższy priorytet) pasowałaby do niej.Zastąpienie jest równoznaczne z dodaniem a,
0
gdyb
spełniony jest warunek na początku listy. (tzn. nie ma potrzeby definiowania oddzielnej reguły{b_, q___} /; cond[b] :> ...
)źródło
Dowiedz się, kiedy (a kiedy nie), aby użyć nazwanych argumentów funkcji czystej
W przypadku golfa kodowego czysto
Function
argumenty są najczęściej przy użyciuSlot
s; np.#
dla pierwszego argumentu,#2
dla drugiego itd. ( więcej szczegółów znajdziesz w tej odpowiedzi ).W wielu przypadkach będziesz chciał zagnieździć
Function
s. Na przykład1##&@@#&
jest to,Function
który bierze listę jako swój pierwszy argument i wyprowadza iloczyn swoich elementów. Oto ta funkcja wTreeForm
:Argumenty przekazywane do poziomu górnej
Function
może jedynie wypełnienieSlot
s iSlotSequence
s obecni na najwyższym poziomie, co w tym przypadku oznacza, żeSlotSequence
w wewnętrznyFunction
nie będzie miał żadnych argumentów sposób dostępu do poziomu górnegoFunction
.Jednak w niektórych przypadkach możesz chcieć, aby
Function
zagnieżdżony w innymFunction
mógł odwoływać się do argumentów zewnętrznychFunction
. Na przykład możesz chcieć czegoś takiegoArray[fun,...]&
, gdzie funkcjafun
zależy od argumentu na najwyższym poziomieFunction
. Dla konkretności, powiedzmy, żefun
resztę kwadratu modułu wejściowego należy przekazać na najwyższy poziomFunction
. Jednym ze sposobów osiągnięcia tego jest przypisanie argumentu najwyższego poziomu do zmiennej:Gdziekolwiek
x
pojawia się w środkuFunction
Mod[#^2,x]&
, będzie odnosić się do pierwszego argumentu na zewnątrzFunction
, podczas gdy#
odniesie się do pierwszego argumentu do wnętrzaFunction
. Lepszym podejściem jest użycie faktu, któryFunction
ma postać dwóch argumentów, gdzie pierwszy argument jest symbolem lub listą symboli, które będą reprezentować nazwane argumenty dlaFunction
(w przeciwieństwie do nienazwanychSlot
). W ten sposób oszczędzamy nam w tym przypadku trzy bajty:
to trzy bajtowy prywatny znakU+F4A1
reprezentujący binarny operator infix\[Function]
. Możesz również użyć postaci binarnejFunction
w innymFunction
:Jest to równoważne z powyższym. Powodem jest to, że jeśli używasz nazwanych argumentów, to
Slot
s iSlotSequences
zakłada się, że należą do następnegoFunction
powyżej, który nie używa nazwanych argumentów.Teraz tylko dlatego, że możemy zagnieżdżać
Function
w ten sposób, nie oznacza, że zawsze powinniśmy. Na przykład, jeśli chcemy wybrać te elementy listy, które są mniejsze niż dane wejściowe, możemy ulec pokusie zrobienia czegoś takiego:W rzeczywistości byłby krótszy w użyciu
Cases
i unikałby potrzebyFunction
całkowicie zagnieżdżonego :źródło
Możesz zapisać bajt, obejście
Prepend
lubPrependTo
:lub
Niestety nie pomaga to w przypadku bardziej powszechnego
Append
, który wydaje się być najkrótszym odpowiednikiemArray.push()
w innych językach.źródło
Mathematica 10.2:
BlockMap
jestPartition
+Map
Ta wskazówka może być również zatytułowana „Przeczytaj wszystkie informacje o wydaniu”. (Dla odniesienia, oto informacje o wersji 10.2 i dzisiejszej wersji 10.3 ).
W każdym razie nawet drobne wydania zawierają wiele nowych funkcji, a jedną z bardziej przydatnych (do gry w golfa) z 10.2 jest nowa
BlockMap
funkcja. Zasadniczo łączyPartition
iMap
, co jest świetne dla golfistów, ponieważPartition
jest używany dość często i jest to naprawdę denerwująco długa nazwa funkcji. Nowa funkcjaPartition
sama się nie skraca , ale ilekroć chcesz mapować funkcję na partycje (co prawdopodobnie zdarza się częściej niż nie), możesz teraz zapisać bajt lub dwa:Oszczędności stają się jeszcze większe, gdy nowa pozycja nienazwanej funkcji pozwala zaoszczędzić sobie kilka nawiasów:
Niestety nie mam pojęcia, dlaczego również nie dodałem
BlockApply
, kiedy byli przy tym ...Pamiętaj też, że
BlockMap
nie obsługuje czwartego parametru, którego można użyćPartition
do uzyskania cyklicznej listy:źródło
Przechowywanie funkcji i wyrażeń w zmiennej
Jeśli twoja odpowiedź kończy się wielokrotnym użyciem tych samych funkcji lub wyrażeń, możesz rozważyć przechowywanie ich w zmiennych.
Jeśli twoje wyrażenie ma długość
l
i używasz gon
razy, zwyklel * n
zużywa bajty.Jeśli jednak przechowujesz ją w zmiennej o długości 1, zajmie to tylko
3 + l + n
bajty (lub2 + l + n
bajty, jeśli przypiszesz zmienną tam, gdzie nie będziesz potrzebowaćCompoundExpression (;)
lub w nawiasach).Rozważmy na przykład prosty problem, znajdowanie podwójnych liczb pierwszych mniejszych niż N.
Można napisać to 54 bajtowe rozwiązanie:
W tym przykładzie funkcja
PrimeQ
jest używana trzy razy.Przypisując
PrimeQ
nazwę zmiennej, można zmniejszyć liczbę bajtów. Oba następujące są 48 bajtów (54 - 6 bajtów):źródło
Aby uzyskać rosnącą listę klucz-wartość, użyj
Sort
zamiastSortBy
W przypadku list takich jak
list = {{1, "world"}, {0, "universe"}, {2, "country"}}
następujące trzy instrukcje są prawie równoważne.Połącz
Select
iSortBy
Czasami musimy wybierać wpisy z większego zestawu i sortować je, aby znaleźć minimum / maksimum. W niektórych okolicznościach dwie operacje można połączyć w jedną.
Na przykład, co najmniej następujące dwie instrukcje są prawie równoważne.
i
1/0
jestComplexInfinity
„większy” niż wszystkie liczby rzeczywiste.Na przykład lista klucz-wartość:
źródło
Spłaszczanie
Array
z##&
Gdy używasz macierzy wielowymiarowej do obliczania listy wyników, które należy spłaszczyć, użyj
##&
jako czwartego argumentu. Zastępuje to głowy tablic##&
(odpowiednikiemSequence
) zamiastList
, więc końcowy wynik będzie (płaski)Sequence
wyników.Porównaj w dwóch wymiarach
Oczywiście
Join@@Array[f,dims]
nadal jest o 2 (lub 3, jeśli można zastosować notację infiksową) bajty krótsze niż{Array[f,dims,1,##&]}
.W co najmniej trzech wymiarach
{Array[f,dims,origin,##&]}
jest zawsze krótszy niż alternatywa, nawet jeśli początkiem jest 1.źródło
Wartości domyślne
Wartości domyślne radzą sobie z brakującymi argumentami wzorca w efektywny sposób. Na przykład, jeśli chcemy wzorować dopasowanie
Exp[c_*x]
w regule dla dowolnej wartościc
, naiwnyużywa o wiele więcej bajtów niż w przypadku użycia wartości domyślnej,
c
gdy tylko jej brakuje:Zastosowanie domyślnie jest oznaczona kropką na wzór:
c_.
.Domyślne wartości wiąże się z czynności: w powyższym przykładzie, operacja jest
Times
wc_.*x
i Brak wartościc_
w ten sposób pobierana z domyślnej wartości zTimes
, co 1.Plus
domyślna wartość od 0:W przypadku
Power
wykładników wartość domyślna to 1:źródło