Tipps zum Golfen in Mathematica

41

Welche allgemeinen Tipps haben Sie zum Golfen in Mathematica? Ich bin auf der Suche nach Ideen, die auf Code-Golf-Probleme im Allgemeinen angewendet werden können, die zumindest etwas spezifisch für Mathematica sind (z. B. "Kommentare entfernen" ist keine Antwort).

Alephalpha
quelle

Antworten:

30

Die folgenden Tipps variieren von den wirtschaftlichsten bis zu den am häufigsten verwendeten:

  1. Verwenden Sie, wo immer möglich, die übergeordneten Befehle von Mathematica, auch sperrige:

  2. Verwendung Graphics and Textfür ASCII-Kunst: zB Sternprogrammierung! und eine analoge Uhr bauen

  3. Spezielle Symbole:

    • Symbole für Logik- und Mengenoperationen anstelle ihrer langen Formnamen: ⋂, ⋃, ∧, ∨

    • Mapund Apply: /@, //@. @@,@@@

  4. Präfix- und Infixnotation:

    • Print@"hello" anstelle von Print["hello"]

    • a~f~b anstelle von f[a,b]

  5. Wenn eine Funktion nur einmal verwendet wird, kann eine reine Funktion ein oder zwei Zeichen einsparen.

  6. Strings in einer Liste verbinden. ""<>{"a","b","c"}Anstatt vonStringJoin@{"a","b","c"}

  7. Listbare Funktionen ausnutzen. Je länger die Listen, desto besser.

    {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}}

DavidC
quelle
2
Es ist immer kürzer zu schreiben (Norm[#-#2]&)als EuclideanDistance.
user202729
32

Einige integrierte Funktionen mit langen Namen können durch kürzere Ausdrücke ersetzt werden.

Zum Beispiel:

  • Total => Tr
  • Transpose=> Threadoder\[Transpose]
  • True => 1<2
  • False => 1>2
  • Times => 1##&
  • Alternatives => $|##&
  • IntegerQ => ⌊#⌋==#&
  • a[[1]] => #&@@a
  • a[[All,1]] => #&@@@a
  • ConstantArray[a,n]=> Array[a&,n]oderTable[a,{n}]
  • Union@a=> {}⋃aodera⋃a
  • ToExpression@n=> FromDigits@nwenn nist eine Zahl
  • Divisible[n,m] => m∣n
  • FromDigits[n,2]=> Fold[#+##&,n]if nist eine Liste von 0s und 1s
  • Complex@z=> {1,I}.zwo zist eine Liste des Formulars{x,y}
Alephalpha
quelle
5
@belisarius 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}}]
Alephalpha
2
Ich denke, dein FoldTrick für FromDigitsfunktioniert auch für jede andere Basis außer 10. ZB FromDigits[n,5]-> Fold[4#+##&,n](mit dem Bonus, ein zusätzliches Byte für Basen 100und zu speichern 1000).
Martin Ender
1
@ mbomb007 3 Bytes in UTF-8. In der Tat ist dieser Charakter U+F3C7.
alephalpha
1
Ich habe endlich 10.3 installiert. Wenn wir vollständige Programme in Betracht ziehen, denke ich nicht, dass dies Echoeine Option ist, da sie >>vor dem Drucken der tatsächlichen Zeichenfolge in STDOUT gedruckt wird (und ein Leerzeichen).
Martin Ender
2
Denn Complex[x,y] => {1,I}.{x,y}denke ich x+y*Iist viel kürzer mit dem gleichen Effekt?
Shieru Asakoto
22

Listen mit wiederholten Werten

Dies ist ein weit verbreiteter Vektor, mit dem man arbeiten kann:

{0,0}

Es stellt sich heraus, dass dies durch ein Byte verkürzt werden kann:

0{,}

Wenn der Vektor länger als zwei Nullen ist, werden noch mehr Bytes gespeichert. Dies kann auch zum Initialisieren von Nullmatrizen verwendet werden, z. B. ergibt das Folgende eine 2x2-Matrix von Nullen:

0{{,},{,}}

Dies kann auch für Werte ungleich Null verwendet werden, wenn sie ausreichend groß oder ausreichend viele oder negativ sind. Vergleichen Sie die folgenden Paare:

{100,100}
0{,}+100
{-1,-1}
0{,}-1
{3,3,3,3}
0{,,,}+3

Denken Sie jedoch daran, dass Sie ab 6 Werten 1~Table~6in diesem Fall besser dran sind (möglicherweise früher, abhängig von den Prioritätsanforderungen).

Der Grund dafür ist, dass ,zwei Argumente in die Liste eingefügt werden. Ausgelassene Argumente (überall in Mathematica) sind implizite Nulls. Darüber hinaus ist Listableund 0*xist Multiplikation 0für fast alle x(mit Ausnahme von Dingen wie Infinityund Indeterminate). Hier ist also, was passiert:

  0{,}
= 0*{,}
= 0*{Null,Null}
= {0*Null,0*Null}
= {0,0}

Für Listen mit 1s können Sie einen ähnlichen Trick anwenden, indem Sie Exponentiationsregeln anwenden. Es gibt zwei verschiedene Möglichkeiten, um Bytes zu speichern, wenn Sie mindestens drei 1s in der Liste haben:

{1,1,1}
1^{,,}
{,,}^0
Martin Ender
quelle
7
+1; Dies zeigt nur, dass Mathematica zwar für alles eine integrierte Funktion hat, das Golfen jedoch eine echte Herausforderung sein kann.
LegionMammal978
Wenn Sie ein Array wollen, das letztendlich mit 1 gefüllt ist, dann 1^{,,,}ist ein Byte kleiner als 0{,,,}+1.
Mischa Lawrow
@ Mischa Lawrow Oh, guter Fang. Das macht es bei drei Werten kürzer und man kann es auch benutzen {,,}^0. Ich werde den Beitrag bearbeiten.
Martin Ender
19

Kennen Sie Ihre reinen Funktionsargumente

Wenn Sie Code golfen, wenden Sie häufig einen funktionalen Ansatz an, bei dem Sie anonyme (reine) Funktionen mit der &Kurzschreibensyntax verwenden. Es gibt viele verschiedene Möglichkeiten, auf die Argumente einer solchen Funktion zuzugreifen, und Sie können sich oft ein paar Bytes sparen, wenn Sie die Möglichkeiten genau kennen.

Zugriff auf einzelne Argumente

Sie wissen dies wahrscheinlich, wenn Sie zuvor reine Funktionen verwendet haben. Die n - te Argument wird als bezeichnet #nund #dient als Alias für #1. Wenn Sie also beispielsweise eine Funktion schreiben möchten, die eine andere Funktion und ihr Argument als Parameter verwendet (um das Argument an diese Funktion zu übergeben), verwenden Sie

#@#2&

Dies funktioniert nicht mit negativen Zahlen (wie Sie sie möglicherweise beim Zugriff auf Listen verwenden).

Zugriff auf benannte Argumente (neu in V10)

Eine der wichtigsten neuen Sprachfunktionen in Mathematica 10 ist Associations, bei denen es sich im Grunde um Schlüsselwertzuordnungen mit beliebigen Schlüsseltypen handelt, die wie folgt geschrieben wurden

<| x -> 1, "abc" -> 2, 5 -> 3 |>

Wenn eine solche Zuordnung als erstes Argument an eine reine Funktion übergeben wird, können Sie auf einige ihrer Argumente als benannte Parameter zugreifen:

{#, #2, #3, #abc, #xyz} & [<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th"]
(* {<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th", "1st", "2nd"} *)

Beachten Sie, dass sich #immer noch wie erwartet auf die gesamte Zuordnung bezieht. Damit die genannten Parameter funktionieren, müssen die Schlüssel Zeichenfolgen sein (dies funktioniert beispielsweise nicht, wenn Sie nicht definierte Variablen verwenden). Diese Zeichenfolgen müssen mit einem Buchstaben beginnen und nur Buchstaben und Ziffern enthalten.

Das "Selbst" -Argument #0

Eine weniger bekannte Funktion ist die, die #0ebenfalls vorhanden ist und Ihnen das Funktionsobjekt selbst gibt. Dies kann in Quines und verallgemeinerten Quines sehr nützlich sein. Tatsächlich ist die kürzeste Mathematica-Quine (die ich kenne)

ToString[#0][] & []

Etwas ärgerlich ist, dass Sie nicht genau die Zeichen erhalten, die Sie eingegeben haben. Wenn Sie sie beispielsweise @für eine Funktionsanwendung verwenden, wird sie weiterhin als gerendert [...]und an einigen Stellen werden Leerzeichen eingefügt. Dadurch wird das Quine normalerweise etwas länger, als Sie es gerne hätten, aber es funktioniert immer, wenn Sie zuerst das Quine golfen und dann nur dessen Ausgabe kopieren - was nun ein echtes Quine sein sollte.

Abgesehen von Quines bedeutet dies auch, dass Sie rekursiven Code schreiben können, ohne Ihre Funktion benennen zu müssen. Vergleichen Sie diese drei (naiven, aber golfenen) Fibonacci-Implementierungen:

f@0=0;f@1=1;f@n_:=f[n-1]+f[n-2]
f@n_:=If[n<2,n,f[n-1]+f[n-2]]
If[#<2,#,#0[#-1]+#0[#-2]]&

Folgen von Argumenten

Hier beginnt die wahre Magie. Sequenzen werden beim Golfen nicht oft verwendet, da Sequenceder Name einfach zu lang ist, um ihn die meiste Zeit wert zu sein. Aber in reinen Funktionen leuchten sie. Wenn Sie mit Sequenzen nicht vertraut sind, ähneln sie im Grunde Splats in anderen Sprachen. Wenn Sie eine Sequenz in einer Listoder der Argumentliste einer Funktion verwenden, werden ihre Elemente automatisch in separate Slots erweitert. Damit

{1, Sequence[2, 3, 4], 5} == {1, 2, 3, 4, 5}
f["a", Sequence[0, {}], "b"] == f["a", 0, {}, "b"]

Nun, in reinen Funktionen ##oder ##1ist eine Folge aller Argumente. Ebenso ##2ist eine Folge aller Argumente aus der zweiten Start, ##3alle Argumente aus der dritten etc. Also zunächst einmal gestartet wurde , können wir reimplementieren nur Sequencewie ##&, spart 5 Byte. Als Beispiel für die Verwendung bietet dies eine Alternative zu Join@@list(siehe diesen Tipp ), die keine Bytes speichert, aber dennoch gut zu wissen ist:

 ##&@@@list

Dadurch wird die erste Ebene einer verschachtelten Liste effektiv geglättet. Was können wir sonst noch damit machen? Hier ist eine 2 Bytes kürzere Alternative zu RotateLeft:

 RotateLeft@list
 {##2,#}&@list

Allein für diese Dinge lohnt es sich, diese Funktion zu berücksichtigen. Wir können es jedoch besser machen! Sequenzen werden wirklich interessant, wenn man bedenkt, dass Operatoren tatsächlich als Funktionen unter der Haube implementiert sind. ZB a+bwertet das eigentlich aus Plus[a,b]. Also, wenn wir das eine Sequenz geben ...

1+##&[1,2,3]
=> Plus[1,##] 
=> Plus[1,1,2,3]
=> 7

Dieser Trick wurde in diesem Tipp verwendet , um ein Byte zu sparen Times, da die Gegenüberstellung technisch gesehen auch nur ein Operator ist:

1##&[1,2,3]
=> Times[1,##]
=> Times[1,1,2,3]
=> 6

Sie können es auch verwenden, um ein Byte zu speichern, Unequalwenn Sie einen Einzelzeichenwert oder eine Variable haben, von der Sie wissen, dass sie nicht in Ihren Argumenten enthalten sind (dies Nfunktioniert wahrscheinlich in 99% der Fälle):

Unequal[a,b,c]
N!=##&[a,b,c]

Dies wird bei unären Operatoren noch interessanter -und /- die beiden letzteren werden tatsächlich in Bezug auf Multiplikation und Potenzierung implementiert. Hier ist eine Liste der Aktionen, bei denen in der letzten Spalte davon ausgegangen wird, dass der Funktion die Argumente übergeben wurden a, b, c:

Operator    Function                Expanded                    Equivalent to

+##         Plus[##]                Plus[a,b,c]                 a+b+c
1##         Times[1,##]             Times[1,a,b,c]              a*b*c
-##         Times[-1,##]            Times[-1,a,b,c]             -a*b*c
x+##        Plus[x,##]              Plus[x,a,b,c]               x+a+b+c
x-##        Plus[x,Times[-1,##]]    Plus[x,Times[-1,a,b,c]]     x-a*b*c
x##         Times[x,##]             Times[x,a,b,c]              x*a*b*c
x/##        Times[x,Power[##,-1]]   Times[x,Power[a,b,c,-1]]    x*a^b^c^-1
##/x        Times[##,Power[x,-1]]   Times[a,b,c,Power[x,-1]]    a*b*c/x
x^##        Power[x,##]             Power[x,a,b,c]              x^a^b^c
##^x        Power[##,x]             Power[a,b,c,#]              a^b^c^x
x.##        Dot[x,##]               Dot[x,a,b,c]                x.a.b.c

Andere gemeinsame Operatoren sind !=, ==, &&, ||. Weniger häufig diejenigen im Auge zu behalten sind |, @*, /*. Abschließend noch ein kleiner Bonus-Trick:

####        Times[##,##]            Times[a,b,c,a,b,c]          (a*b*c)^2

Experimentieren Sie weiter mit diesen und lassen Sie mich wissen, wenn Sie andere nützliche oder besonders interessante Anwendungen finden!

Martin Ender
quelle
15

Sqrt@2oder 2^.5=>√2

a[[1]]=>a〚1〛

#+#2&=>+##&

Flatten@a=> Join@@a(manchmal)

Function[x,x^2]=> xx^2oder#^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

Chyanog
quelle
1
Beachten Sie, dass beim Messen in Bytes mit und jeweils 3 Bytes benötigt werden (UTF8
vorausgesetzt
12

Operatoren als Funktionen

Inspiriert von Dennis 'jüngster Entdeckung für Julia dachte ich, ich würde dies für Mathematica untersuchen. Mir war bewusst, dass Mathematica eine große Anzahl nicht verwendeter Operatoren definiert, aber ich habe ihm nie viel Aufmerksamkeit geschenkt.

Als Referenz finden Sie hier die Liste aller Operatoren in Form einer Rangfolgetabelle. Das Dreieck in der letzten Spalte gibt an, ob dieser Operator eine eingebaute Bedeutung hat oder nicht. Nicht alle, die sich nicht leicht definieren lassen, können es aber die meisten.

Praktischerweise gibt es zwei nicht verwendete Operatoren mit einem Codepunkt von weniger als 256, sodass sie als einzelne Bytes in einer ISO 8859-1-codierten Quelldatei verwendet werden können:

  • ± (0xB1) kann entweder als unärer Präfixoperator oder als binärer Infixoperator verwendet werden.
  • · (0xB7) kann als variabler oder n-stelliger Infixoperator für n> 2 verwendet werden.

Es gibt jedoch noch einen Haken: Aus irgendeinem Grund benötigen Sie beim Definieren dieser Operatoren ein Leerzeichen vor ihnen, oder Mathematica versucht, eine Multiplikation zu analysieren. Wenn Sie sie verwenden, benötigen Sie jedoch keine Leerzeichen:

±x_:=2x
x_ ±y_:=x+y
x_ ·y_ ·z_:=x*y+z
Print[±5]  (* 10 *)
Print[3±4] (*  7 *)
Print[3·4·5] (* 17 *)

Vergleichen Sie dies mit:

f@x_:=2x
x_~g~y_:=x+y
h[x_,y_,z_]:=x*y+z
Print[f@5]   (* 10 *)
Print[3~g~4] (*  7 *)
Print[h[x,y,z]] (* 17 *)

Das spart also ein Byte bei der Definition der Funktion und zwei Byte bei der Verwendung. Beachten Sie, dass die Definition von ·keine Bytes für vier Operanden speichert und Bytes für mehr Operanden anfängt, aber die Verwendung spart möglicherweise immer noch Bytes, abhängig von der Rangfolge der in den Argumenten verwendeten Operatoren. Es ist auch zu beachten, dass Sie kostengünstig eine variable Funktion definieren können, die dann viel effizienter aufgerufen werden kann:

x_ ·y__:={y}
Print[1·2·3·4·5] (* {2, 3, 4, 5} *)

Beachten Sie jedoch, dass es nicht einfach ist, diese variablen Funktionen mit einem einzigen Argument aufzurufen. (Sie könnten es tun CenterDot[x]oder ##&[]·xaber wenn Sie es tatsächlich brauchen, haben Sie eine gute Chance, mit einer anderen Lösung besser dran zu sein.)

Dies spart natürlich nichts für Lösungen, bei denen eine unbenannte Funktion ausreicht, aber manchmal müssen Sie Hilfsfunktionen für die spätere Verwendung definieren, und manchmal ist es kürzer, benannte Funktionen zu definieren, z. B. um verschiedene Definitionen für verschiedene Parameter einzurichten. In diesen Fällen kann die Verwendung eines Operators eine angemessene Menge an Bytes einsparen.

Beachten Sie, dass für die Verwendung dieser ISO 8859-1-codierten Dateien $CharacterEncodingein kompatibler Wert festgelegt werden muss, wie dies bei Windows der Fall ist WindowsANSI. Auf einigen Systemen ist dies die Standardeinstellung, bei UTF-8der diese Codepunkte nicht aus einzelnen Bytes gelesen werden können.

Martin Ender
quelle
Das ist wirklich großartig, ich wusste nicht, dass Mathematica eine Liste von Operatoren hat und gab sogar deren Rangfolge an. Diese beiden Operatoren, die Sie gefunden haben, werden sich bestimmt als nützlich erweisen.
Meilen
8

Auswählen von Werten basierend auf einer Ganzzahl

Die naive Herangehensweise, zwischen yund zu wählen z, je nachdem ob es xist 0oder 1ist

If[x<1,y,z]

Es gibt jedoch einen kürzeren Weg:

y[z][[x]]

Dies funktioniert, weil in diesem Fall [[0]]das Headeines Ausdrucks gegeben wird y, während [[1]]nur das erste Element gegeben wird - in diesem Fall das erste Argument z.

Sie können dies sogar verwenden, um zwischen mehr als zwei Werten zu wählen:

u[v,w][[x]]

Beachten Sie, dass dies nicht funktioniert, wenn ues sich um eine Funktion handelt, die tatsächlich etwas ergibt. Es ist wichtig, dass Mathematica so bleibt, u[v,w]wie es ist. Dies funktioniert jedoch in den meisten Fällen, auch wenn ues sich bei a um eine Zahl, eine Zeichenfolge oder eine Liste handelt.

Credits für diesen Trick gehen an Alephalpha - das habe ich in einer seiner Antworten entdeckt.

Wenn x1-basiert statt null-basiert ist, verwenden Sie einfach

{y,z}[[x]]

oder

{u,v,w}[[x]]

In einigen seltenen Fällen können Sie sogar die Tatsache nutzen, dass die Multiplikation für einige Werte nicht ausgewertet wird:

{"abc","def"}[[x]]
("abc""def")[[x]]

Beachten Sie aber , dass Mathematica tatsächlich Neuordnungs die Argumente, eine Multiplikation , wenn es nicht ausgewertete bleibt, so dass die oben ist identisch zu

("def""abc")[[x]]
Martin Ender
quelle
8

Alternativen zu Length

Dies wurde mit einigen Vorschlägen von LegionMammal978 und Misha Lavrov komplett neu geschrieben. Vielen Dank an beide.

In vielen Fällen Lengthkann mit etwas gekürzt werden Tr. Die Grundidee ist, die Eingabe in eine Liste von 1s umzuwandeln, so dass sie Trsummiert werden, was dann der Länge der Liste entspricht.

Die gebräuchlichste Methode hierfür ist 1^x(für eine Liste x). Das funktioniert , weil Powerist Listableund 1^nfür die meisten Atom Werte nist nur 1(einschließlich aller Zahlen, Strings und Symbole). Damit können wir schon ein Byte sparen:

Length@x
Tr[1^x]

Dies setzt natürlich voraus, dass dies xein Ausdruck mit höherer Priorität ist als ^.

Wenn xnur 0s und 1s enthalten sind, können wir ein weiteres Byte mit speichern Factorial(vorausgesetzt, es xhat eine höhere Priorität als !):

Length@x
Tr[x!]

In einigen seltenen Fällen xmöglicherweise eine niedrigere Priorität als, ^aber immer noch eine höhere Priorität als die Multiplikation. In diesem Fall hat es auch eine niedrigere Priorität als @, also müssen wir wirklich mit vergleichen Length[x]. Ein Beispiel für einen solchen Operator ist .. In diesen Fällen können Sie weiterhin ein Byte mit diesem Formular speichern:

Length[x.y]
Tr[0x.y+1]

Abschließend noch einige Anmerkungen zu den Listen, auf denen dies funktioniert:

Wie oben erwähnt, funktioniert dies bei flachen Listen, die nur Zahlen, Zeichenfolgen und Symbole enthalten. Es funktioniert jedoch auch auf einigen tieferen Listen, obwohl es tatsächlich etwas anderes berechnet. Bei einem n- D-Rechteckarray erhalten TrSie mit die kürzeste Dimension (im Gegensatz zur ersten). Wenn Sie wissen, dass die äußerste Dimension die kürzeste ist, oder wenn Sie wissen, dass sie alle gleich sind, sind die Tr-Ausdrücke immer noch äquivalent zu Length.

Martin Ender
quelle
3
Nur fand eine noch kürzere Lösung: Length@x == Tr[1^x]. Sollte mit den meisten Listen funktionieren.
LegionMammal978
@ LegionMammal978 das ist unglaublich, danke :). Ich werde es bald bearbeiten.
Martin Ender
1
Jetzt habe ich zweimal festgestellt, dass ich in dem speziellen Fall, in dem nur Nullen und Einsen enthalten sind , ein Byte speichere , Tr[x!]anstatt es Tr[1^x]zu xverwenden.
Mischa Lawrow
@ Mischa Lawrow Das ist wirklich ordentlich! :)
Martin Ender
7
  1. Entdecken Sie rekursive Lösungen - Mathematica ist ein Multiparadigma, aber der funktionale Ansatz ist oft der wirtschaftlichste. NestWhilekann eine sehr kompakte Lösung für Suchprobleme sein NestWhileListund FoldListist leistungsstark, wenn Sie die Ergebnisse von Zwischeniterationen zurückgeben oder verarbeiten müssen. Map (/@), Apply (@@, @@@), MapThread, Und wirklich alles auf Wolframs Functional Programming Dokumentation Seite ist potent Sachen.

  2. Verkürzte Form zum Inkrementieren / Dekrementieren - Zum Beispiel, anstatt While[i<1,*code*;i++]Sie tun können
    While[i++<1,*code*]

  3. Vergessen Sie nicht, dass Sie vorab inkrementieren / dekrementieren können - zum Beispiel --ianstelle von i--. Dies kann manchmal einige Bytes im umgebenden Code einsparen, indem eine vorbereitende Operation beseitigt wird.

  4. Fazit zu David Carrahers Nr. 5: Wenn dieselbe Funktion mehrmals verwendet wird, können durch Zuweisen eines Symbols Bytes gespart werden. Wenn Sie beispielsweise ToExpression4-mal in einer Lösung verwenden, t=ToExpressionkönnen Sie sie t@*expression*danach verwenden. Bevor Sie dies tun, sollten Sie jedoch prüfen, ob die wiederholte Anwendung derselben Funktion eine Möglichkeit für einen wirtschaftlicheren rekursiven Ansatz darstellt.

Jonathan Van Matre
quelle
MapThreadkann oft durch ersetzt werden \[Transpose]. TIO .
user202729
7

Nicht verwenden, {}wenn Sie verwenden @@@.

In einigen Fällen können Sie auf einen Ausdruck wie den folgenden stoßen:

f@@@{{a,b},{c,d}}

Es ist möglich, Bytes durch Schreiben zu reduzieren:

f@@@{a|b,c|d}

Alternativeshat eine sehr niedrige Priorität, daher ist es im Allgemeinen in Ordnung, Ausdrücke zu schreiben (eine bemerkenswerte Ausnahme sind reine Funktionen; Sie können sie nur im ganz linken Element von verwenden Alternatives).

f@@@{f@a|b~g~1,#^2&@c|d@2}

Beachten Sie, dass f@@a|b|c(anstelle von f@@{a,b,c}) nicht funktioniert, da Applyes eine höhere Priorität als hat Alternative.

In diesem Fall sollten Sie einfach verwenden f@@{a,b,c}.

JungHwan min
quelle
6

Nur Mathematica 10

Bedienerformulare

Mathematica 10 unterstützt sogenannte "Operator-Formulare", dh es können grundsätzlich einige Funktionen ausgeführt werden. Durch das Aufrufen einer Funktion wird eine neue Funktion erstellt, indem einer ihrer Operatoren festgelegt wird. Angenommen, Sie verwenden SortBy[list, somereallylongfunction&]viele verschiedene lists. Früher hätte man wahrscheinlich zugewiesen SortByzu sund die reine Funktion fso

s=SortBy;
f=somereallylongfunction&;
list1~s~f;
list2~s~f;
list3~s~f;

Jetzt können Sie curry SortBy, was bedeutet, dass Sie jetzt tun können

s=SortBy[somereallylongfunction&];
s@list1;
s@list2;
s@list3;

Das gleiche funktioniert für viele andere Funktionen, die eine Liste oder Funktionsargument nehmen, einschließlich (aber nicht beschränkt auf) Select, Map, Nearestetc.

ybeltukov über Mathematica.SE konnte eine vollständige Liste dieser erstellen :

{"AllTrue", "AnyTrue", "Append", "Apply", "AssociationMap", "Cases", 
 "Count", "CountDistinctBy", "CountsBy", "Delete", "DeleteCases", 
 "DeleteDuplicatesBy", "Extract", "FirstCase", "FirstPosition", 
 "FreeQ", "GroupBy", "Insert", "KeyDrop", "KeyExistsQ", "KeyMap", 
 "KeySelect", "KeySortBy", "KeyTake", "Map", "MapAt", "MapIndexed", 
 "MatchQ", "MaximalBy", "MemberQ", "Merge", "MinimalBy", "NoneTrue", 
 "Position", "Prepend", "Replace", "ReplacePart", "Scan", "Select", 
 "SelectFirst", "SortBy", "StringCases"}

Zusammensetzung und RightComposition

Es gibt neue Abkürzungen für Composition( @*) und RightComposition( /*). Ein offensichtlich ausgefallenes Beispiel, in dem diese Zeichen speichern können, ist in den folgenden drei entsprechenden Zeilen zu sehen

Last@Range@# & /@ Range[5]
Last@*Range /@ Range[5]
Range /* Last /@ Range[5]
Martin Ender
quelle
5

Schreiben Sie keine 0-Argument-Funktionen

Code wie dieser wird nicht benötigt:

f[]:=DoSomething[1,2]
(*...*)
f[]
(*...*)
f[]

Sie können einfach eine Variable mit verwenden :=, um eine Neubewertung der rechten Seite zu erzwingen:

f:=DoSomething[1,2]
(*...*)
f
(*...*)
f

Dies bedeutet auch, dass Sie jede Aktion, die Sie häufig ausführen (auch wenn es sich nur n++um eine Art handelt ), auf Kosten von 5 Byte einem einzelnen Zeichen zuordnen können. Im Falle, dass n++es sich nach dem vierten Gebrauch auszahlt:

n++;n++;n++;n++
f:=n++;f;f;f;f
Martin Ender
quelle
5

Verwenden Sie %, um eine freie Variable zu erhalten

Dieser Tipp gilt nur, wenn die REPL-Umgebung von Mathematica angenommen werden kann. %ist nicht definiert, wenn Code als Skript ausgeführt wird.

Wenn Sie können die Verwendung der REPL Eigenschaften machen, dies nicht tun:

a=someLongExpression;some[other*a,expression@a,using^a]

Denken Sie stattdessen daran, dass Mathematica den zuletzt ausgewerteten Ausdruck (mit Zeilenende) in %folgendem Verzeichnis speichert :

someLongExpression;
some[other*%,expression@%,using^%]

Die hinzugefügte Newline kostet ein Byte, aber Sie sparen zwei, indem Sie sie entfernen a=, sodass insgesamt ein Byte eingespart wird .

In einigen Fällen (z. B. wenn Sie den Wert von aohnehin drucken möchten ) können Sie sogar die folgenden ;zwei Bytes weglassen:

someLongExpression
some[other*%,expression@%,using^%]

Ein oder zwei Bytes mögen ziemlich klein erscheinen, aber dies ist ein wichtiger Fall, da das Extrahieren von wiederholten Ausdrücken (was eine sehr häufige Technik ist) beim Golfen viel nützlicher ist:

Die normale Technik zum Extrahieren von wiederholten Ausdrücken kostet vier Bytes Overhead, die bei weiteren Verwendungen des Ausdrucks eingespart werden müssen. Hier ist eine kurze Tabelle der Mindestanzahl von Verwendungen eines Ausdrucks (nach Länge des Ausdrucks) zum Extrahieren in eine benannte Variable, um etwas zu speichern:

Length   Min. Uses
2        6
3        4
4        3
5        3
6        2
...      2

Mit der unbenannten Variablen können einige Bytes viel häufiger gespeichert werden:

When ; is required                        When ; can be omitted

Length   Min. Uses                        Length   Min. Uses
2        5                                2        4
3        3                                3        3
4        3                                4        2
5        2                                ...      2
...      2

Ich glaube nicht , %%oder %nkann für den Golfsport verwendet werden, denn wenn man sich zumindest nicht zweimal verwenden, können Sie nur den Ausdruck in Ordnung bringen , wo es gebraucht wird . Und wenn Sie es zweimal verwenden, hebt das zusätzliche Zeichen im Variablennamen die Einsparungen auf, die durch das Weglassen einiger Zeichen entstehen x=.

Martin Ender
quelle
Beachten Sie, dass es im Skriptmodus nicht funktioniert.
alephalpha
@alephalpha Was ist der Skriptmodus?
Martin Ender
Ein Mathematica-Skript .
alephalpha
@alephalpha Oh, richtig, ich habe mein Gehirn dort für eine Sekunde abgeschaltet ... das würde bedeuten, dass es überhaupt nicht wirklich verwendet werden kann, es sei denn, die REPL-Umgebung kann angenommen werden.
Martin Ender
5

Prüfen, ob eine Liste sortiert ist

Dies ist im Wesentlichen eine Konsequenz aus diesem Tipp, aber dies ist eine ausreichend häufige Aufgabe, die meiner Meinung nach eine eigene Antwort rechtfertigt.

Der naive Weg zu überprüfen, ob eine Liste in Ordnung ist, ist zu verwenden

OrderedQ@a

Wir können ein Byte besser machen

Sort@a==a

Dies funktioniert jedoch nicht, wenn wir nicht das haben, was wir bereits in einer Variablen einchecken möchten. (Wir brauchen etwas, Sort[a=...]==adas unnötig lang ist.) Es gibt jedoch eine andere Option:

#<=##&@@a

Das Beste daran ist, dass hiermit überprüft werden kann, ob die Eingabe für die gleiche Byteanzahl in umgekehrter Reihenfolge sortiert ist:

#>=##&@@a

Ein weiteres Byte kann gespeichert werden, wenn a) wir wissen, dass die Listenelemente verschieden sind und b) wir eine Untergrenze zwischen 0 und 9 kennen (einschließlich; oder Obergrenze für umgekehrte Sortierreihenfolge):

0<##&@@a
5>##&@@a

Um herauszufinden, warum dies funktioniert, lesen Sie "Sequences of arguments" in dem oben verlinkten Tipp.

Martin Ender
quelle
Alternativ (streng) senken gebunden für Reverse-sortiert auch Arbeit: ##>0&@@a. Ähnliches gilt für die obere Schranke für sortiert.
user202729
@ user202729 Oh guter Punkt, zögern Sie nicht zu bearbeiten (ansonsten werde ich versuchen, es am Wochenende zu tun, wenn ich mich erinnere).
Martin Ender
5

Eine Zeichenfolge wiederholen

Anstatt zu StringRepeat[str,n]benutzen (0Range[n]+str)<>"". Oder wenn stres nicht auf Slot-Argumente ankommt, ist es noch besser, Array[str&,n]<>""wie in diesem Tipp beschrieben.

Feersum
quelle
1
Fazit: Anstatt zu StringRepeat[s,n+1]verwenden Array[s&,n]<>s(auch wenn Sie bereits n+1eine Variable haben).
Martin Ender
BesserTable[str,n]<>""
Attinat
5

Wenn Sie eine Liste mit in umgekehrter Reihenfolge sortierten Nummern benötigen, verwenden Sie diese nicht

Reverse@Sort@x

aber

-Sort@-x

um sechs Bytes zu sparen. Das Sortieren nach einem negativen Wert ist auch in folgenden SortBySzenarien hilfreich :

Reverse@SortBy[x,Last]
SortBy[x,-Last@#&]
Martin Ender
quelle
2
Was ist -Sort@-x?
JungHwan Min
1
@JungHwanMin Oh, äh, ja, das ist viel besser. :)
Martin Ender
4

Sie können einen Ausdruck einfügen, in Breakdem ein oder zwei Zeichen gespeichert werden können. Beispiel ( andere Details sind der Übersichtlichkeit halber nicht dargestellt ):

result = False;
Break[]

kann in verwandelt werden

Break[result = False]

ein Zeichen speichern. Wenn der betreffende Ausdruck keine niedrigere Priorität als die Funktionsanwendung hat, können Sie sogar ein anderes Zeichen speichern:

Print@x;
Break[]

kann in verwandelt werden

Break@Print@x

Obwohl nicht dokumentiert, Breakscheint das Argument to von der umgebenden Schleife zurückgegeben zu werden, was möglicherweise zu noch mehr Einsparungen führen kann.

Martin Ender
quelle
4

sVerwenden Sie, um alle Leerzeichen aus einer Zeichenfolge zu entfernen

StringSplit@s<>""

Das heißt, verwenden Sie StringSplitdie Standardeinstellung (aufgeteilt in Nicht-Whitespace-Komponenten) und fügen Sie sie einfach wieder zusammen. Das gleiche ist wahrscheinlich immer noch das kürzeste, wenn Sie ein anderes Zeichen oder einen anderen Teilstring entfernen möchten:

s~StringSplit~"x"<>""
Martin Ender
quelle
4

Alternativen zu Range

Eine sehr häufige Aufgabe ist es, eine Art Funktion auf alle Zahlen von 1 bis a anzuwenden n(normalerweise als Eingabe angegeben). Grundsätzlich gibt es drei Möglichkeiten, dies zu tun (am Beispiel einer unbenannten Identitätsfunktion):

#&/@Range@n
Array[#&,n]
Table[i,{i,n}]

Ich tendiere dazu, mich für den ersten zu entscheiden (aus welchem ​​Grund auch immer), aber dies ist selten die beste Wahl.

Verwenden Sie Arraystattdessen

Das obige Beispiel zeigt, dass using Arraydieselbe Byteanzahl hat. Es hat jedoch den Vorteil, dass es sich um einen einzelnen Ausdruck handelt. Insbesondere wenn Sie das Ergebnis mit einer Funktion weiterverarbeiten möchten, können fSie die Präfixnotation verwenden, die ein Byte darüber speichert Range:

f[#&/@Range@n]
f@Array[#&,n]

Darüber hinaus können Sie möglicherweise Klammern um Ihre unbenannte Funktion weglassen, die Sie möglicherweise mit benötigen Range, z

15/(#&)/@Range@n
15/Array[#&,n]

Wenn Sie es nicht weiter verwenden möchten (oder mit einem Operator, der eine geringere Priorität hat), können Sie sich stattdessen Arrayselbst in Infixnotation schreiben und auch ein Byte speichern:

#&/@Range@n
#&~Array~n

Daher Arrayist mit ziemlicher Sicherheit besser als Range.

Verwenden Sie Tablestattdessen

Jetzt muss die Tabelle 3 Bytes oder mindestens 2 Bytes umfassen, wenn die Infixnotation eine Option ist:

#&/@Range@n
i~Table~{i,n}

Wenn Sie keine Infix-Notation verwenden, Tablekönnen Sie möglicherweise Klammern weglassen, wenn Ihre Funktion aus mehreren Anweisungen besteht:

(#;#)&/@Range@n
Table[i;i,{i,n}]

Dies ist noch länger, bringt aber zusätzliche Einsparungen in dem unten genannten Fall.

Die wirklichen Einsparungen ergeben sich aus der Tatsache, dass Tableder laufenden Variablen ein Name gegeben werden sollte. Oft haben Sie unbenannte Funktionen verschachtelt, bei denen Sie die äußere Variable in einer der inneren Funktionen verwenden möchten. Wenn das passiert, Tableist kürzer als Range:

(i=#;i&[])&/@Range@n
Table[i&[],{i,n}]
i&[]~Table~{i,n}

Sie speichern nicht nur die Zeichen für die Zuweisung i, sondern können die Funktion möglicherweise auch auf eine einzelne Anweisung reduzieren, sodass Sie die Infix-Notation darüber verwenden können. Als Referenz Arrayist auch in diesem Fall länger, aber immer noch kürzer als Range:

(i=#;i&[])&~Array~n

Wann würden Sie tatsächlich verwenden Range?

Wann immer Sie keinen Funktionsaufruf benötigen, um die Werte zu verarbeiten, zB wenn das Mapping über eine vektorisierte Operation durchgeführt werden kann. Zum Beispiel:

5#&~Array~n
5Range@n
#^2&~Array~n
Range@n^2

Natürlich ist es auch kürzer, wenn Sie überhaupt keine Funktion abbilden möchten, z

Mean@Array[#&,n]
Mean@Range@n
Martin Ender
quelle
Endlich jemand anderes, der f/@Range[x]regelmäßig verwendet ...
LegionMammal978
4

Finden der kleinsten Zahl, die eine Bedingung erfüllt

Einige Konstrukte wie i=1;While[cond[i],i++]sind in Ordnung, aber es gibt eine Alternative, die zwei Bytes kürzer ist:

1//.i_/;cond[i]:>i+1

Der obige Code ersetzt wiederholt eine Zahl idurch, i+1solange die Bedingung erfüllt ist cond[i]. In diesem Fall ibeginnt um 1.

Beachten Sie, dass die standardmäßige maximale Anzahl von Iterationen 2 ^ 16 (= 65536) beträgt. Wenn Sie mehr Iterationen als das brauchen, Whilewäre besser. ( MaxIterations->∞ist zu lang)

JungHwan min
quelle
4

Missbrauch Kurzschlussauswertung

Sie können manchmal durch Ifeinen logischen Operator ersetzen .

Angenommen, Sie möchten eine Funktion erstellen, mit der überprüft wird, ob eine Zahl eine Primzahl 2*(number) - 1ist.

If[PrimeQ@#,Print[2#-1]]&

Es ist kürzer, wenn Sie &&stattdessen verwenden:

PrimeQ@#&&Print[2#-1]&

Selbst wenn Sie mehrere Ausdrücke haben, speichern Sie immer noch Byte (s):

If[PrimeQ@#,a++;Print[2#-1]]&

PrimeQ@#&&a++&&Print[2#-1]&
(* or *)
PrimeQ@#&&(a++;Print[2#-1])&

Sie können ||für Fälle verwenden, in denen die Bedingung sein soll False:

If[!PrimeQ@#,Print[2#-1]]&
(* or *)
If[PrimeQ@#,,Print[2#-1]]&
(* can become *)
PrimeQ@#||Print[2#-1]&

Diese Tricks funktionieren, weil logische Operatoren kurzgeschlossen werden können . Das zweite Argument und danach müssen nicht einmal gültige boolesche Ausdrücke sein.

Dies funktioniert natürlich nicht, wenn Sie den Rückgabewert von Ifbenötigen oder wenn Sie sowohl wahre als auch falsche Argumente von benötigen If.

JungHwan min
quelle
3

Hier ist eine Liste mit vielen Bedienereingabeformularen, die viele Dinge verkürzen können. Einige davon wurden in anderen Posts erwähnt, aber die Liste ist lang und ich bin immer überrascht, ein paar neue Dinge dort zu finden:

Martin Ender
quelle
Dies funktioniert jedoch nur, wenn der Operator weniger UTF-8-Bytes verwendet.
LegionMammal978
3

Verwenden Optional (:)

Optional (:) kann verwendet werden, um Listen in Ersetzungen zu erweitern, ohne dass eine separate Regel für die Erweiterung definiert werden muss.

Diese Antwort von mir und diese Antwort von @ngenisis sind Beispiele.

Verwendungszweck

... /. {p___, a_: 0, b_, q___} /; cond[b] :> ...

Der obige Ersatz verwendet zuerst das Muster {p___, a_, b_, q___}und findet eine Übereinstimmung, bdie eine bestimmte Bedingung erfüllt.

Wenn keine solche Übereinstimmung gefunden wird, wird ausgelassen a_und stattdessen gesucht {p___, b_, q___}. awird nicht in die Suche einbezogen und es wird davon ausgegangen, dass der Wert vorhanden ist 0.

Beachten Sie, dass die zweite Mustersuche nur bam Anfang der Liste funktioniert . Wenn ein bWert, der eine Bedingung erfüllt, in der Mitte liegt, {p___, a_, b_, q___}würde er stattdessen (mit höherer Priorität) mit ihm übereinstimmen.

Das Ersetzen entspricht dem Voranstellen von a, 0wenn eine bBedingung am Anfang der Liste erfüllt ist. (dh es muss keine separate Regel definiert werden {b_, q___} /; cond[b] :> ...)

JungHwan min
quelle
3

Wissen, wann (und wann nicht) benannte reine Funktionsargumente verwendet werden sollen

Für Code-Golf werden reine FunctionArgumente am häufigsten mit Slots referenziert . zB #für das erste Argument, #2für das zweite usw. (siehe diese Antwort für weitere Details).

In vielen Fällen möchten Sie Functions verschachteln . Beispiel: 1##&@@#&is a Functionnimmt eine Liste als erstes Argument und gibt das Produkt seiner Elemente aus. Hier ist diese Funktion in TreeForm:

Bildbeschreibung hier eingeben

An die oberste Ebene übergebene Argumente Functionkönnen nur Slots und SlotSequences füllen , die auf der obersten Ebene vorhanden sind. Dies bedeutet in diesem Fall, dass SlotSequencedie inneren Functionkeine Möglichkeit haben, auf Argumente auf der obersten Ebene zuzugreifen Function.

In einigen Fällen möchten Sie jedoch möglicherweise, dass ein Functionin einem anderen Element verschachteltes FunctionElement Argumente nach außen verweist Function. Zum Beispiel möchten Sie vielleicht so etwas wie Array[fun,...]&, wo die Funktion funvon einem Argument auf der obersten Ebene abhängt Function. Nehmen wir der Vollständigkeit halber an, dass funder Rest des Quadrats seines Eingangsmoduls den Eingang zur obersten Ebene geben soll Function. Eine Möglichkeit, dies zu erreichen, besteht darin, das Argument der obersten Ebene einer Variablen zuzuweisen:

(x=#;Array[Mod[#^2,x]&,...])&

Wo immer es xim Inneren erscheint Function Mod[#^2,x]&, bezieht es sich auf das erste Argument im Äußeren Function, wohingegen #es sich auf das erste Argument im Inneren bezieht Function. Ein besserer Ansatz besteht darin, die Tatsache zu verwenden, dass Functioneine Form mit zwei Argumenten vorliegt, wobei das erste Argument ein Symbol oder eine Liste von Symbolen ist, die benannte Argumente für die Function(im Gegensatz zu unbenannten Slots) darstellen. Das spart uns in diesem Fall drei Bytes:

xArray[Mod[#^2,x]&,...]

ist das Drei-Byte-Zeichen U+F4A1für den privaten Gebrauch, das den binären Infix-Operator darstellt \[Function]. Sie können auch die binäre Form eines Functionanderen verwenden Function:

Array[xMod[x^2,#],...]&

Dies entspricht dem oben Gesagten. Der Grund ist, dass, wenn Sie benannte Argumente verwenden, von Slots und SlotSequencesangenommen wird, dass sie zu den nächsthöheren gehören, Functiondie keine benannten Argumente verwenden.

Nur weil wir Functions auf diese Weise nisten können, heißt das nicht, dass wir es immer tun sollten. Wenn wir beispielsweise die Elemente einer Liste auswählen möchten, die kleiner als die Eingabe sind, könnten wir versucht sein, Folgendes zu tun:

Select[...,xx<#]&

Es wäre tatsächlich kürzer zu verwenden Casesund die Notwendigkeit einer Verschachtelung Functiongänzlich zu vermeiden :

Cases[...,x_/;x<#]&
Genisis
quelle
2

Sie können ein Byte speichern, indem Sie umgehen Prependoder PrependTo:

l~Prepend~x
{x}~Join~l
{x,##}&@@l

oder

l~PrependTo~x
l={x}~Join~l
l={x,##}&@@l

Leider hilft dies nicht für die häufiger Append, die Array.push()in anderen Sprachen das kürzeste Äquivalent zu einem zu sein scheint .

Martin Ender
quelle
2

Mathematica 10.2: BlockMapist Partition+Map

Dieser Tipp könnte auch den Titel "Alle Versionshinweise lesen" tragen. (Als Referenz finden Sie hier die Versionshinweise für 10.2 und hier für die heutige Version 10.3 .)

Auf jeden Fall enthalten auch kleinere Releases eine Fülle neuer Funktionen, und eine der nützlicheren (für das Golfen) ab 10.2 ist die neue BlockMapFunktion. Es kombiniert im Wesentlichen Partitionund Mapist ideal für Golfer, da Partitiones ziemlich oft verwendet wird und es ist ein wirklich ärgerlich langer Funktionsname. Die neue Funktion wird sich nicht Partitionvon selbst verkürzen , aber wenn Sie eine Funktion auf die Partitionen abbilden möchten (was wahrscheinlich häufig vorkommt), können Sie jetzt ein oder zwei Bytes speichern:

#&/@l~Partition~2
BlockMap[#&,l,2]
#&/@Partition[l,3,1]
BlockMap[#&,l,3,1]

Die Einsparungen werden noch größer, wenn Sie sich durch die neue Position der unbenannten Funktion einige Klammern sparen können:

#&@@(#&/@Partition[l,3,1])
#&@@BlockMap[#&,l,3,1]

Leider habe ich keine Ahnung, warum sie nicht auch hinzugefügt haben, BlockApplywährend sie dabei waren ...

Beachten Sie auch, dass BlockMapder vierte Parameter, mit Partitiondem Sie eine zyklische Liste erstellen können, nicht unterstützt wird :

Partition[Range@5, 2, 1, 1]
(* Gives {{1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 1}} *)
BlockMap[f, Range@5, 2, 1, 1]
(* Nope... *)
Martin Ender
quelle
2

Speichern von Funktionen und Ausdrücken in einer Variablen

Wenn Ihre Antwort dieselben Funktionen oder Ausdrücke mehrmals verwendet, können Sie sie in Variablen speichern.

Wenn Ihr Ausdruck Länge ist lund Sie ihn nmal verwenden, würde er normalerweise l * nBytes verbrauchen.

Wenn Sie es jedoch in einer Variablen der Länge 1 speichern, werden nur 3 + l + nBytes benötigt (oder 2 + l + nBytes, wenn Sie die Variable dort zuweisen, wo Sie sie nicht benötigen, CompoundExpression (;)oder Klammern).


Betrachten wir zum Beispiel ein einfaches Problem, bei dem zwei Primzahlen kleiner als N sind.

Man könnte diese 54-Byte-Lösung schreiben:

Select[Range@#,PrimeQ@#&&(PrimeQ[#+2]||PrimeQ[#-2])&]&

In diesem Beispiel wird die Funktion PrimeQdreimal verwendet.

Durch die Vergabe PrimeQeines Variablennamens kann die Byteanzahl reduziert werden. Beide der folgenden sind 48 Bytes (54 - 6 Bytes):

Select[p=PrimeQ;Range@#,p@#&&(p[#+2]||p[#-2])&]&
Select[Range@#,(p=PrimeQ)@#&&(p[#+2]||p[#-2])&]&
JungHwan min
quelle
2

Verwenden Sie Sortanstelle von, um eine aufsteigende Schlüsselwertliste zu erhaltenSortBy

Für Listen wie list = {{1, "world"}, {0, "universe"}, {2, "country"}}sind die folgenden drei Aussagen fast gleichwertig.

SortBy[list,#[[1]]&]
list~SortBy~First
Sort@list

Kombinieren SelectundSortBy

Manchmal müssen wir Einträge aus einer größeren Menge auswählen und sortieren, um ein Minimum / Maximum zu finden. Unter bestimmten Umständen können zwei Operationen zu einer zusammengefasst werden.

Zum Beispiel sind die folgenden beiden Aussagen zumindest fast gleichwertig.

SortBy[Select[l,SomeFormula==SomeConstant&],SortValue&]
SortBy[l,SortValue+99!(SomeFormula-SomeConstant)^2&]

und

SortBy[Select[l,SomeFormula!=SomeConstant&],SortValue&]
SortBy[l,SortValue+1/(SomeFormula-SomeConstant)&]

1/0ist ComplexInfinity, was "größer" ist als alle reellen Zahlen.

Für eine Schlüsselwertliste zum Beispiel:

{SortValue,#}&/@SortBy[Select[l,SomeFormula==SomeConstant],SortValue&]
Sort[{SortValue+99!(SomeFormula-SomeConstant)^2,#})&/@l]
Keyu Gan
quelle
1

Abflachen Arraymit##&

Verwenden Sie ##&als viertes Argument ein mehrdimensionales Array, um eine Liste der Ergebnisse zu berechnen, die reduziert werden müssen. Dadurch werden die Köpfe des Arrays durch ##&(äquivalent zu Sequence) ersetzt List, sodass das Endergebnis eine (flache) SequenceErgebnismenge ist.

Vergleichen Sie in zwei Dimensionen

{Array[f,dims,origin,##&]}
Join@@Array[f,dims,origin]

Natürlich sind Join@@Array[f,dims] immer noch 2 (oder 3, wenn die Infixnotation verwendet werden kann) Bytes kürzer als {Array[f,dims,1,##&]}.

In drei oder mehr Dimensionen {Array[f,dims,origin,##&]}ist immer kürzer als die Alternative, auch wenn der Ursprung 1 ist.

{Array[f,dims,1,##&]}
f~Array~dims~Flatten~2
attinat
quelle
1

Standardwerte

Standardwerte behandeln fehlende Musterargumente auf effiziente Weise. Wenn wir zum Beispiel Exp[c_*x]eine Regel für einen beliebigen Wert von c, the naïve, mit einem Muster abgleichen möchten

Exp[x] + Exp[2x] /. {Exp[c_*x] -> f[c], Exp[x] -> f[1]}
(*    f[1] + f[2]    *)

Verwendet viel mehr Bytes, als wenn der Standardwert verwendet wird, cwenn er fehlt:

Exp[x] + Exp[2 x] /. Exp[c_.*x] -> f[c]
(*    f[1] + f[2]    *)

Die Verwendung eines Standard wird mit einem Punkt nach dem Muster angegeben: c_..

Vorgabewerte sind mit Operationen verknüpft: Im obigen Beispiel befindet sich die Operation Timesin c_.*x, und ein fehlender Wert für c_wird daher dem mit Times1 verknüpften Vorgabewert entnommen . Für Plusist der Vorgabewert 0:

Exp[x] + Exp[x + 2] /. Exp[x + c_.] -> f[c]
(*    f[0] + f[2]    *)

Für PowerExponenten ist der Standardwert 1:

x + x^2 /. x^n_. -> p[n]
(*    p[1] + p[2]    *)
römisch
quelle