Welche allgemeinen Tipps haben Sie zum Golfen in Julia? Ich bin auf der Suche nach Ideen, die generell auf Code-Golf-Probleme angewendet werden können, die zumindest etwas spezifisch für Julia sind (z. B. "Kommentare entfernen" ist keine Antwort).
Welche allgemeinen Tipps haben Sie zum Golfen in Julia? Ich bin auf der Suche nach Ideen, die generell auf Code-Golf-Probleme angewendet werden können, die zumindest etwas spezifisch für Julia sind (z. B. "Kommentare entfernen" ist keine Antwort).
Antworten:
HINWEIS: Das Folgende kann einige veraltete Tipps enthalten, da Julia strukturell noch nicht ganz stabilisiert ist.
Ein paar Tricks, um ein paar Zeichen zu speichern
\ =div
Sie und Sie können dann a\b
anstelle von eingeben div(a,b)
. Beachten Sie das Leerzeichen - dies ist erforderlich, um zu vermeiden, dass es als "\ =" - Operator analysiert wird. Beachten Sie auch, dass Sie bei Überlastung auf der Ebene der REPL-Eingabeaufforderung (\)=Base.(\)
oder verwenden \ =Base. \
, um es zurückzusetzen. HINWEIS: Für einige Funktionen sind vorhandene UTF-8-Operatoren vordefiniert, z. B. ÷
für div
, wie von Alex A angegeben.a>0?"Hi":""
, verwendet "Hi"^(a>0)
einen Byte oder für boolean a zu speichern, verwenden "Hi"^a
zu drei Bytes zu speichern.a=split("Hi there"," ")
Sie a[1]
und a[2]
durch Verwendung möglicherweise vermeiden a,b=split("Hi there"," ")
, was als a
und bezeichnet werden b
kann, wobei drei Bytes für jede Verwendung auf Kosten von nur zwei zusätzlichen Zeichen bei der Zuweisung eingespart werden. Tun Sie dies natürlich nicht, wenn Sie mit Vektoroperationen arbeiten können.[]
- für Arrays ist der Ausdruck A[]
äquivalent zu A[1]
. Beachten Sie, dass dies nicht für Strings funktioniert, wenn Sie das erste Zeichen erhalten möchten, oder für Tuples.==[]
für Arrays und ==()
Tupel. in ähnlicher Weise für das Negativ verwenden !=[]
und !=()
. Verwenden Sie ==""
für Zeichenfolgen >""
"" leer, aber nicht leer, da "" lexikografisch vor allen anderen Zeichenfolgen steht.x<=1&&"Hi"
kann so geschrieben werden x>1||"Hi"
, dass ein Zeichen gespeichert wird (solange die Rückkehr des Booleschen nicht wichtig ist).in('^',s)
statt contains(s,"^")
. Wenn Sie andere Zeichen verwenden können, können Sie mit etwas mehr speichern '^'∈s
, beachten Sie jedoch, dass dies ∈
in UTF-8 3 Byte sind.minimum(x)
oder maximum(x)
, verwenden Sie min(x...)
oder max(x...)
, um ein Zeichen aus Ihrem Code zu entfernen, wenn Sie wissen x
, dass mindestens zwei Elemente vorhanden sind. Wenn Sie wissen, dass alle Elemente von x
nicht negativ sind, können Sie auch minabs(x)
oder verwendenmaxabs(x)
r"(?m)match^ this"
, Typen r"match^ this"m
, Speicher drei Zeichen.reverse(x)
sind ein Byte länger als flipud(x)
und führen dieselbe Operation aus, sodass letztere besser ist.{[1,2]}
nicht {1,2}
). Für Julia 0.4 benötigen Sie diese Klammern Any[[1,2]]
.end
Array-Indizierung verwenden, wird sie automatisch in die Länge des Arrays / der Zeichenfolge konvertiert. Anstatt also k=length(A)
, benutzen Sie A[k=end]
3 Zeichen zu speichern. Beachten Sie, dass dies möglicherweise nicht vorteilhaft ist, wenn Sie k sofort verwenden möchten. Dies funktioniert auch in einem mehrdimensionalen Fall - A[k=end,l=end]
wird die Größe jeder Dimension von erhalten A
- (k,l)=size(A)
ist in diesem Fall jedoch um ein Byte kürzer, verwenden Sie es also nur, wenn Sie sofort auf das letzte Element gleichzeitig zugreifen möchten.A[k=1:end]
In diesem Fall k
wird ein Iterator-Abgleich durchgeführt 1:length(A)
. Dies kann nützlich sein, wenn Sie gleichzeitig auch ein Array verwenden möchten A
.collect(A)
verwenden Sie [A...]
, was dasselbe bewirkt und 4 Bytes spart."$(s[i])"
oder dec(s[i])
für Ausdrücke oder Variablen mit mehreren Zeichen und "$i"
für Variablen mit einem Zeichen.?:
anstelle von &&
oder ||
für bedingte Zuweisung - das heißt, wenn Sie einen Auftrag ausführen soll nur auf eine Bedingung, können Sie ein Byte speichern , indem er cond?A=B:1
statt cond&&(A=B)
oder cond?1:A=B
nicht cond||(A=B)
. Beachten Sie, dass es sich 1
hier um einen Dummy-Wert handelt.union
oder ∪
anstelle vonunique
- union(s)
, um das Gleiche zu tun unique(s)
und dabei ein Byte zu speichern. Wenn Sie Nicht-ASCII-Zeichen verwenden können, ∪(s)
geschieht dasselbe und ∪
kostet nur 3 Bytes anstelle der 5 Bytes in union
.split("Hi there")
da das Musterargument standardmäßig ein Leerzeichen ist.
Durch die Neudefinition von Operatoren können viele Bytes in Klammern und Kommas gespeichert werden.
Vergleichen Sie für ein unäres Beispiel die folgenden rekursiven Implementierungen der Fibonacci-Sequenz:
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
Der neu definierte Operator behält seinen ursprünglichen Vorrang.
Beachten Sie, dass wir nicht einfach !
zu Gunsten von tauschen können ~
, da dies ~
bereits für Ganzzahlen definiert ist, während dies !
nur für Boolesche Werte definiert ist.
Auch ohne Rekursion ist die Neudefinition eines Operators kürzer als die Definition einer Binärfunktion. Vergleichen Sie die folgenden Definitionen eines einfachen Teilbarkeitstests.
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
Im Folgenden wird veranschaulicht, wie Sie einen Binäroperator neu definieren, um die Ackermann-Funktion zu berechnen:
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
Beachten Sie, dass dies ^
sogar länger ist als die Verwendung eines regulären Bezeichners, da seine Priorität zu hoch ist.
Wie schon erwähnt
m|n=m>0?m-1|(n<1||m|~-n):n+1 # 28 bytes
würde nicht für ganzzahlige Argumente funktionieren, da |
dies in diesem Fall bereits definiert ist. Die Definition für Ganzzahlen kann mit geändert werden
m::Int|n::Int=m>0?m-1|(n<1||m|~-n):n+1 # 38 bytes
aber das ist unerschwinglich lang. Es funktioniert jedoch, wenn wir ein float als linkes Argument und eine ganze Zahl als rechtes Argument übergeben.
Lassen Sie sich nicht zu leicht von Faktor (n) verführen. Die verführerische Funktion factor(n)
der Basisbibliothek weist einen schwerwiegenden Fehler auf: Sie gibt die Faktorisierung Ihrer Ganzzahl in einem ungeordneten Dict
Typ zurück. Daher ist es kostspielig collect(keys())
und collect(values())
möglicherweise auch ein cat
und ein sort
, um die gewünschten Daten daraus zu holen. In vielen Fällen kann es billiger sein, nur nach Probedivisionen zu rechnen. Traurig aber wahr.
"Karte verwenden" map
ist eine großartige Alternative zum Schleifen. Machen Sie sich den Unterschied zwischen map
und bewusst map!
und nutzen Sie die vorhandenen Funktionen der letzteren, wenn Sie können.
Die Verwendung von Mapreduce mapreduce
erweitert die Funktionalität von Map noch weiter und kann zu einer erheblichen Einsparung von Bytes führen.
Anonyme Funktionen sind großartig! ..besonders wenn an die oben genannten map
Funktionen übergeben.
Kumulative Array-Funktionen cumprod
, cumsum
die Flavorful- cummin
und die anderen ähnlich benannten Funktionen ermöglichen kumulative Operationen entlang einer angegebenen Dimension eines n-dimensionalen Arrays. (Oder * un * angegeben, wenn das Array 1-d ist)
Kurznotation für Alle Wenn Sie alle Dimensionen eines mehrdimensionalen Arrays (oder Dict) auswählen möchten A[Any,2]
, können Sie z. B. Bytes mit speichernA[:,2]
Verwenden Sie die einzeilige Notation für Funktionen, anstatt function f(x) begin ... end
Sie oft zu vereinfachenf(x)=(...)
Verwenden Sie den ternären Operator. Bei If-Then-Else-Konstruktionen mit einem Ausdruck kann dies Platz sparen. Vorsichtsmaßnahmen: Obwohl dies in einigen anderen Sprachen möglich ist, können Sie den Teil nach dem Doppelpunkt in Julia nicht auslassen. Außerdem ist der Operator in Julia Ausdrucksebene, sodass Sie ihn nicht für die bedingte Ausführung ganzer Codeblöcke verwenden können.
if x<10 then true else false end
vs
x<10?true:false
Dies ist auch in anderen Sprachen möglich, in der Regel jedoch länger als die einfache Methode. Die Fähigkeit von Julia, seine unären und binären Operatoren neu zu definieren, macht es jedoch ziemlich golfen.
Zum Erzeugen der Additions-, Subtraktions-, Multiplikations- und Divisionstabelle für die natürlichen Zahlen von 1 bis 10 könnte man beispielsweise verwenden
[x|y for x=1:10,y=1:10,| =(+,-,*,÷)]
die definieren den binären Operator |
wie +
, -
, *
und ÷
, berechnet dann x|y
für jede Operation und x
und y
in den gewünschten Bereichen.
Dies funktioniert auch für unäre Operatoren. Um beispielsweise die komplexen Zahlen 1 + 2i , 3-4i , -5 + 6i und -7-8i , ihre Negative, ihre komplexen Konjugate und ihre multiplikativen Inversen zu berechnen , könnte man verwenden
[~x for~=(+,-,conj,inv),x=(1+2im,3-4im,-5+6im,-7-8im)]
die definiert den unären Operator ~
wie +
, -
, conj
und inv
, berechnet dann ~x
für alle gewünschten komplexen Zahlen.
Fallpermutation (unär)
Schlüsselwörter können manchmal unmittelbar auf Konstanten folgen, ohne dass ein Leerzeichen oder ein Semikolon erforderlich ist. Beispielsweise:
n->(for i=1:n n-=1end;n)
Beachten Sie das Fehlen eines Leerzeichens zwischen 1
und end
. Dies gilt auch für das end
Auftreten nach einem engen Paren, dh )end
.
Führen Sie Integer - Division unter Verwendung ÷
anstatt div()
oder einen Betreiber zu überlasten. Beachten Sie, dass dies ÷
in UTF-8 2 Byte wert ist.
Verwenden Sie vec()
oder A[:]
(für einige Arrays A
), anstatt reshape()
wann immer dies möglich ist.
Erstellen Sie Funktionen anstelle vollständiger Programme, wenn dies in den Herausforderungsregeln zulässig ist. Es ist kürzer, eine Funktion zu definieren, die Eingaben akzeptiert, als Variablen durch Lesen von stdin zu definieren. Beispielsweise:
n->(n^2-1)
n=read(STDIN,Int);n^2-1
Variablen können innerhalb des Arguments zu einer Funktion inkrementiert werden. Das Folgende ist zum Beispiel meine Antwort auf die Herausforderung " Find the Next 1-Sparse Binary Number" :
n->(while contains(bin(n+=1),"11")end;n)
Dies ist kürzer als das Inkrementieren n
innerhalb der Schleife.
Eingeführt in Julia 0.5. Es ist wie eine Karte, verwendet jedoch weniger Zeichen und überträgt weniger Zeichen, sodass Sie weniger Lambdas schreiben können, um mit den Dingen umzugehen.
Eher, als:
map(f,x)
-- 8 Charaktere.f.(x)
- 5 ZeichenBesser noch:
map(a->g(a,y),x)
- 16 Zeicheng.(x,[y])
- 9 Zeichen