Tipps zum Golfen in MATL

20

MATL ist eine von Luis Mendo entwickelte Golfsprache . MATL hat sich als äußerst wettbewerbsfähig erwiesen und Einsendungen in anderen Golfsprachen wie Pyth, CJam und Jelly oft geschlagen .

Was sind einige nützliche Tipps zum Golfen in MATL? (Bitte wie immer einen Tipp pro Antwort!)

Stewie Griffin
quelle
5
Es ist auf jeden Fall ein großer Vorteil, wenn Sie Matlab / Octave kennen. Einige Tricks von Tipps zum Golfen in Matlab und Tipps zum Golfen in Octave, die auch in MATL verwendet werden.
Fehler
Vorschlag: Es sieht so aus, als ob accumarray( XQ) ziemlich mächtig sein kann (möglicherweise sogar mehr als in MATLAB / Octave, da diese Längenfunktionsgriffe praktische numerische Codes haben), aber ich kenne es nicht gut genug, um es mit guten Beispielen zu veranschaulichen. Wenn es tatsächlich nützlich ist, könnte jemand eine Antwort mit Ideen zur Verwendung erstellen?
Sundar - Reinstate Monica

Antworten:

7

Kennen Sie die vordefinierten Literale

Einige von ihnen behalten zwar Informationen bei, wenn sie in die Zwischenablage kopiert werden, haben jedoch alle einen vordefinierten Wert.

  • F, drückt 0 (eigentlich Falsch )
  • T, drückt 1 (tatsächlich wahr )
  • H, drückt 2 (vordefinierter Wert der Zwischenablage)
  • I, drückt 3 (vordefinierter Wert der Zwischenablage)
  • K, drückt 4 (vordefinierter Zwischenablage-Wert)
  • J, drückt 0 + 1j (vordefinierter Wert der Zwischenablage)

Ich bin mir nicht sicher, ob ich alle vordefinierten Werte abgedeckt habe.

Adnan
quelle
Der Vollständigkeit halber (und für den Fall, dass Sie Ihrer Antwort etwas hinzufügen möchten): Jede Ebene der Zwischenablage Lhat auch einen vordefinierten Wert, aber sie sind für spezielle Zwecke gedacht (und nicht für allgemeine Werte). Zum Beispiel 1Lgibt [1 0](der als Index verwendet wird 1:end), 2Lgibt [0 -1 1](für 1:-1:end). Auch Funktionen lund Onehmen 0 Eingänge standardmäßig aktiviert und produziert 0und 1jeweils
Luis Mendo
Ich verstehe nicht, wie nützlich das ist ... Kann ich nicht einfach schreiben 4?
Cyoce
@Cyoce Der Nutzen besteht darin, ein Leerzeichen als Trennzeichen zu vermeiden. Wenn du pushen willst 1, dann 4geht 14das nicht. Du würdest brauchen 1 4. Oder 1Kum ein Byte zu speichern
Luis Mendo
@ LuisMendo ah, ich verstehe. Ich nehme an, es wurde die 1-stellige Zahl nur Methode verwendet (nicht sicher warum)
Cyoce
1
Ein anderer Fall, wenn Kanstelle von 4praktisch ist, ist: 1-4bedeutet: drücken 1, dann drücken -4; während 1-Kbedeutet: drücken 1, subtrahieren von was auch immer unten im Stapel ist, dann drücken4
Luis Mendo
5

Das & Meta-Funktion (Alternative Eingabe- / Ausgabespezifikation)

Die traditionelle Art, die Anzahl der Eingabeargumente anzugeben, die an eine Funktion übergeben werden sollen, ist die Verwendung der $Meta-Funktion

2$:     % Two-input version of :

Um die Anzahl der Ausgabeargumente festzulegen, können Sie auch die #Meta-Funktion verwenden, die entweder die Anzahl der Ausgabeargumente angibt.

2#S     % Two-output version of sort

Übergeben Sie eine Zahl, die größer ist als die Anzahl der für eine Funktion definierten Ausgabeargumente, wird nur die mod(N, numberOfOutputs) + 1Ausgabe bereitgestellt.

4#S     % Get only the second output of sort

Sie können zusätzlich ein logisches Array als Eingabe angeben #, um nur bestimmte Ausgabeargumente abzurufen.

TFT#u   % Three output version of unique and discard the second output

Alle diese Eingabe- / Ausgabespezifikationen sind praktisch , erhöhen jedoch die Bytezahl sehr schnell. Um dies zu bewältigen, hat MATL die &Meta-Funktion in Version 17.0.0 eingeführt . Dies& Metafunktion fungiert als Verknüpfung für eine bestimmte Eingabe- oder Ausgabespezifikation für eine Funktion. Mal sehen, was das bedeutet.

In unserem obigen Beispiel wollten wir die Version von mit zwei Eingängen verwenden :(erstellt einen Vektor mit Werten mit gleichem Abstand). Während die Standardanzahl von Eingangsargumente :IS 1(ein Array aus erzeugt [1...N]), ist es sehr üblich , dass ein Benutzer den Startwert des Bereichs spezifizieren möchte , die den zweiten Eingang erfordert. Also für :haben wir definiert &für eine Verknüpfung zu sein 2$.

10      % Push 10 to the stack
12      % Push 12 to the stack
2$:     % Create an array: [10, 11, 12] 

Jetzt wird folgendes, ein Byte speichern !

10 12 &:

Wie können wir die alternative Anzahl von Argumenten bestimmen?

Die Eingabe- / Ausgabespezifikation, in die &übersetzt wird, ist funktionsspezifisch , sodass wir die Byte-Einsparungen optimieren.

Der Abschnitt mit den Eingabe- / Ausgabeargumenten in der Hilfebeschreibung für jede Funktion wurde aktualisiert, um anzugeben, um welche alternative Anzahl von Ein- / Ausgängen es sich handelt (falls vorhanden). Die mögliche Anzahl der Eingabe- oder Ausgabeargumente wird als Bereich angezeigt und die Standardwerte für jedes Argument sind in Klammern angegeben. Die Eingabe- / Ausgabespezifikation, durch die ersetzt werden kann, &wird nach dem /Zeichen in Klammern angezeigt .

Hier ist der Abschnitt mit den Ein- / Ausgabeargumenten in der Hilfebeschreibung für :

 +- Min-Max range of # of inputs
 |        +----- Alt. Default # of inputs
 |        |
 V        V
1--3 (1 / 2); 1 <--- Possible / Default # of outputs
      ^       
      |       
  Default # of inputs

Wie hast du was festgestellt? & für jede Funktion bedeutet?

Sehr vorsichtig. Mithilfe der StackExchange-API konnten wir alle MATL-Antworten herunterladen, die jemals in einer PPCG-Herausforderung verwendet wurden. Durch Analysieren jeder der Antworten konnten wir dann die Häufigkeit bestimmen, mit der jede Eingabe- / Ausgabespezifikation für jede Funktion verwendet wurde. Anhand dieser Informationen konnten wir dann objektiv die Eingabe- / Ausgabespezifikation identifizieren, die die &Metafunktion für jede Funktion darstellen sollte. Manchmal gab es keinen klaren Sieger, so viele Funktionen haben sich derzeit nicht &definiert.

Hier ist das Skript, das wir verwendet haben (leider ist es in MATLAB geschrieben und nicht MATL geschrieben).

Und hier ist ein Beispiel für das Histogramm von $/ #usage

Suever
quelle
1
Dieses Feature wurde vorgeschlagen von @Suever. Ursprünglich &hieß das "Anzahl der Eingänge um 1 gegenüber dem Standard erhöhen". Sein Vorschlag erwies sich als viel nützlicher
Luis Mendo
5

Machen Sie sich mit den Wahrheits- / Falschdefinitionen von MATL vertraut

Während true( T) und false( F) eindeutig die Wahrheits- bzw. Falschausgabe darstellen, ist die weitestgehend vereinbarte Definition von Wahrheit / Falsch gibt uns ein wenig mehr Flexibilität in MATL.

Die Definition besagt:

if (x)
    disp("x is truthy");
else
    disp("x is falsy");
end

Wir können also einen schnellen MATL-Wahrheits- / Falschtest schreiben, der alle Eingaben durchläuft und anzeigt, ob sie als wahr oder falsch eingestuft wurden

` ? 'truthy' } 'falsey' ]DT

Hier ist eine Online-Version.

Was dies in MATL bedeutet

In MATL (und daher in MATLAB und Octave) bedeutet dies, dass eine Bedingung als wahr betrachtet wird, wenn sie nicht leer ist und die realen Komponenten aller ihrer Werte nicht Null sind . Es gibt zwei Teile, die hervorgehoben werden sollten.

  1. Nicht-Null : Dies bedeutet genau das, ungleich Null ( ==). Dies schließt positive Zahlen, negative Zahlen, Nicht-Null-Zeichen usw. ein. Sie können dies einfach überprüfen, indem Sie einen bestimmten Wert in einen logicalWert ( g) umwandeln oder verwenden~~

    F           % Falsy
    T           % Truthy
    0           % Falsy
    1           % Truthy
    2           % Truthy
    -1          % Truthy
    'a'         % Truthy
    ' '         % Truthy (ASCII 32)
    char(0)     % Falsy  (ASCII 0)  
    
  2. Alle Werte : Normalerweise betrachten wir Skalare als wahr oder falsch, aber in MATL können Skalare, Zeilenvektoren, Spaltenvektoren oder sogar mehrdimensionale Matrizen ausgewertet werden, und sie werden nur dann als wahr angesehen, wenn jeder einzelne Wert wahr ist Nicht-Null (wie oben definiert), sonst sind sie falsch. Hier einige Beispiele zur Veranschaulichung

    [1, 1, 1]           % Truthy
    [1, 0, 0]           % Falsey
    [1, 1, 1; 1, 1, 1]  % Truthy
    [1, 0, 1; 1, 1, 1]  % Falsey
    'Hello World'       % Truthy
    

Der Fall mit einer Kante ist, wie oben erwähnt, ein leeres Array [], das immer als falsch betrachtet wird ( Beispiel ).

Wie kann ich das nutzen, um besser zu golfen?

Wenn in der Abfrage nur erwähnt wird, dass Ihre Ausgabe wahr oder falsch sein sollte, können Sie die obige Definition wahrscheinlich ausnutzen, um ein paar Bytes Ihrer Antwort zu sparen. Um Verwirrung zu vermeiden, wird empfohlen, dass Sie in Ihre Antwort einen Link zum obigen Online-Wahrheits- / Falschtest einfügen, um zu erläutern, wie MATL-Wahrheits- / Falschwerte funktionieren.

Einige konkrete Beispiele:

  • Eine Antwort endet mit A. Wenn für die Abfrage eine wahrheitsgemäße oder falsche Ausgabe erforderlich ist und Sie Ihre Antwort mit all( A) beenden , um einen Skalar zu erstellen, können Sie dieses letzte Byte entfernen und Ihre Antwort bleibt korrekt (es sei denn, die Ausgabe ist []da []ist falseaber []Aist true).

  • Sicherstellen, dass ein Array nur einen eindeutigen Wert enthält : Verwendet &=anstelle von un1=. Wenn alle Werte in einem Array gleich sind, wird bei einem Vergleich der übertragenen Elemente in Bezug auf die Gleichheit eine N x NMatrix aller Werte erstellt . Wenn nicht alle Werte gleich sind, enthält diese Matrix einige 0Werte und wird daher als falsch betrachtet.

Suever
quelle
4

Implizite Eingabe

Die meisten Funktionen akzeptieren eine bestimmte Anzahl von Eingaben. Diese Eingaben werden von der Oberseite des Stapels übernommen. Wenn der obere Bereich des Stapels nicht genügend Argumente enthält, wird das verbleibende Argument aus der Eingabe gezogen. (Siehe Abschnitt 7.3 in der Dokumentation) Ich möchte die ursprüngliche Erklärung zitieren:

Implizite Eingaben können wie folgt betrachtet werden: Der Stapel wird unterhalb des Bodens unbegrenzt erweitert, dh an den Positionen 0, -1, -2, ... mit Werten, die anfangs nicht definiert sind, die jedoch im laufenden Betrieb über implizite Eingaben aufgelöst werden . Diese Eingaben werden vom Benutzer nur dann abgefragt, wenn sie benötigt werden, und zwar in der Reihenfolge, in der sie benötigt werden. Wenn mehrere Eingaben gleichzeitig erforderlich sind, folgen sie der normalen Stapelreihenfolge, dh, die Eingabe, die am tiefsten im (erweiterten) Stapel liegt, wird zuerst eingegeben.

fehlerhaft
quelle
2
Implizite Eingabe ist eine Funktion, die von @flawr
Luis Mendo vorgeschlagen wurde
6
@flawr muss ein wirklich kluger Typ sein. : D
Fehler
3

Logische Arrays können häufig als numerische Arrays verwendet werden

Sie können häufig die " TF" Notation anstelle von Array - Literalen aus Nullen und Einsen verwenden. Zum Beispiel FTFist dasselbe wie [0,1,0], nur dasFTF das logicalWerte erzeugt , keine doubleWerte. Dies ist normalerweise kein Problem, da jede arithmetische Operation logische Werte als Zahlen behandelt. Zum Beispiel FTFQgibt [1,2,1]( Qist "um 1 erhöhen").

In einigen Fällen kann die Umwandlung einer Zahl in eine Binärdatei kürzer sein. Beispielsweise,[1,0,1] , TFTund 5Bsind gleich; wieder mit der Vorsicht, dass die beiden letzteren logicalWerte sind.


Ein Fall, in dem der Unterschied zwischen TF(logisch) und [1 0](numerisch) von Bedeutung ist, liegt vor, wenn er als Indizes verwendet wird. Ein Array des Typs, logicalder als Index verwendet wird, bedeutet: Elemente auswählen, die entsprechen T, diejenigen verwerfen, die entsprechen F. Also [10 20]TF)produziert 10(wähle das erste Element aus), wohingegen [10 20][1 0])produziert [10 20](der Index [1 0]hat die Interpretation 1:end, das heißt, wähle alle Elemente des Arrays aus).

Luis Mendo
quelle
3

Für Schleife der Größe n-1

Sollten Sie sie ersetzen

tnq:"...

mit

td"...

um bis zu einem ganzen Byte oder mehr zu speichern .

Sanchises
quelle
@ Luis wahr! Ich dachte, dass man vielleicht den ursprünglichen Vektor braucht, der geloopt wird, aber das ist auch beim ersten Ansatz nicht möglich. Wird diese Bemerkung entfernen.
Sanchises
Sie sparen jedoch nicht unbedingt 1 Byte. Sie sparen 1 oder 2 , je nachdem , ob Sie benötigen @/ X@in der Schleife oder nicht. Vielleicht können Sie einfach "Bytes speichern" sagen
Luis Mendo
3

Verschieben Sie Dinge von hinter der Schleife in die Schleife, um das implizite Ende auszunutzen

Loop - endAnweisungen ]können, werden weggelassen , wenn kein Code hinter ihnen her ist. Sie werden implizit vom MATL-Parser gefüllt.

Wenn Sie also Dinge von nach der Schleife in die Schleife verschieben können, können Sie das Finale speichern ] .

Im folgenden Beispiel wird die Anzahl der nachgestellten Nullen in der Fakultät einer Zahl ermittelt N(siehe hier ):

  • Der Code wiederholt sich von 1bis N.
  • Für jede dieser Zahlen werden die Primfaktoren berechnet und bestimmt, wie oft 5vorhanden ist.
  • Die Antwort ist die akkumulierte Anzahl von 5Auftritten (dies funktioniert, weil für jeden 5mindestens einer vorhanden ist 2).

Die erste Idee war :"@Yf5=]vs(beachte, dass es Aussagen nach der Schleife gibt):

:      % Range from 1 to implicit input
"      % For each number in that vector
  @    %   Push that number
  Yf   %   Vector of prime factors (with repetitions)
  5=   %   True for entries that equal `5`, and `false` for the rest
]      % End for
v      % Concatenate all vectors as a column vector
s      % Sum. Implicitly display

Da vstandardmäßig alle Stapelinhalte verkettet sind, können sie in die Schleife verschoben werden. Und da die Addition assoziativ ist, skann sie auch verschoben werden. Das steht ]am Ende des Codes und kann daher weggelassen werden :"@Yf5=vs:

:      % Range from 1 to implicit input
"      % For each number in that vector
  @    %   Push that number
  Yf   %   Vector of prime factors (with repetitions)
  5=   %   True for entries that equal `5`, and `false` for the rest
  v    % Concatenate all vectors so far as a column vector
  s    % Sum. Inplicitly end loop and display
Luis Mendo
quelle
Ich kenne keinen Cent dieser hieroglyphenähnlichen Schriftsprache, aber ich werde einen großen Teil meiner Zeit darauf verwenden, sie die nächsten drei Monate vielleicht zu studieren.
13.
@ Agawa001 :-) Sie werden feststellen, dass es Matlab ziemlich ähnlich ist. Hier können Sie auch Fragen stellen oder Kommentare abgeben
Luis Mendo
3

Kürzere Möglichkeit, ein leeres numerisches Array zu definieren, wenn der Stapel leer ist

Zum Verschieben eines leeren numerischen Arrays, das Sie normalerweise verwenden []. Wenn der Stapel jedoch leer ist, können Sie ein Byte mit speichernv . Diese Funktion verknüpft standardmäßig alle Stapelinhalte vertikal. Wenn der Stapel also leer ist, wird das leere Array erstellt.

Sie können es zum Beispiel hier in Aktion sehen .

Luis Mendo
quelle
2

Einige Funktionen sind gegenüber MATLAB oder Octave erweitert

Wenn Sie aus MATLAB oder Octave kommen, werden Sie feststellen, dass viele MATL-Funktionen den Funktionen in diesen Sprachen ähnlich sind. Aber in einigen von ihnen wurde die Funktionalität erweitert.

Betrachten Sie als Beispiel die reshapeFunktion von MATLAB , die in MATL entspricht e . Der Code - Schnipsel reshape([10 20 30 40 50 60], 2, 3)und reshape([10 20 30 40 50 60], 2, [])bedeutet jeweils „umformen den Zeilenvektor [10 20 30 40 50 60in eine 2 × 3 - Matrix“ oder „in eine 2-reihigen Matrix mit so vielen Spalten wie benötigt“. Das Ergebnis ist also in beiden Fällen das 2D-Array

10    30    50
20    40    60

Etwas wie reshape([10 20 30 40 50 60], 2, 2)oder reshape([10 20 30 40 50 60], 5, [])würde einen Fehler wegen inkompatibler Größen geben. Im ersten Fall entfernt MATL jedoch Elemente ( versuchen Sie es online! ) Oder füllt sie im zweiten mit Nullen ( online ausprobieren! )

10 30
20 40 

und

10 60
20  0
30  0
40  0
50  0

Andere Funktionen , die erweiterte Funktionalität im Vergleich zu ihren MATLAB Pendants sind (nicht erschöpfende Liste) haben S( sort), Yb( strsplit), m( ismember), h( horzcat), v( vertcat), Zd( gcd), Zm( lcm), YS( circshift), YA( dec2base), ZA( base2dec), Z"( blanks).

Luis Mendo
quelle
1

Ruft den Index des ersten Nicht-Null-Elements ab, falls vorhanden

Die fFunktion gibt die Indizes aller Nicht-Null-Elemente eines Arrays an. Häufig möchten Sie den Index des ersten Elements ungleich Null. Das wäre f1): Bewerben Sie sich fund wählen Sie das erste Element aus. Wenn das ursprüngliche Array jedoch keinen Wert ungleich Null enthält, fwird ein leeres Array ausgegeben ([] ) , und der Versuch, das erste Element auszuwählen, führt zu einem Fehler.

Eine übliche, robustere Anforderung besteht darin, den Index des ersten Elements zu erhalten falls mindestens eines vorhanden ist , und []ansonsten. Dies könnte mit einer ifVerzweigung nach getan werden f, aber das ist byteteuer. Besser ist fX<es, die Minimalfunktion X<auf den Ausgang von anzuwenden f.X<Gibt ein leeres Array zurück, wenn seine Eingabe ein leeres Array ist.

Probieren Sie es online! (Beachten Sie, dass ein leeres Array überhaupt nicht angezeigt wird). Oder sieht ein Beispiel hierfür bei der Arbeit hier .

Luis Mendo
quelle
1

Generieren Sie einen Bereich, der so lang wie ein bestimmtes Array ist

TL; WR : verwendenf Option, n:wenn das Array nur Elemente ungleich Null enthält.


Häufig muss ein Array generiert werden, [1 2 ... L]in dem Ldie Anzahl der Elemente eines bestimmten Arrays angegeben ist. Die Standardmethode hierfür istn: . Beispielsweise nimmt der Code tn:*einen numerischen Vektor als Eingabe und berechnet jeden Eintrag multipliziert mit seinem Index.

Wenn das angegebene Array garantiert nur Einträge ungleich Null enthält (z. B. positive ganze Zahlen oder eine Zeichenfolge mit druckbaren Zeichen), n:kann durch ersetzt werdenf , wodurch ein Array mit den Indizes von Einträgen ungleich Null erstellt wird. So wird der obige Code tf*, der 1 Byte spart.

Einige ausführlichere Beispiele: 1 , 2 , 3 .

Luis Mendo
quelle
1

Effizientes Definieren von numerischen Array-Literalen

Es gibt einige Möglichkeiten, wie Sie beim Definieren von numerischen Array-Literalen Bytes speichern können. Links werden zu Beispielantworten gegeben, die diese verwenden. Diese wurden mit dem Analyseskript ermittelt erstellt @Suever .

Verkettung und vordefinierte Literale

Bei Arrays mit kleinen Zahlen können Sie manchmal Verkettungen (Funktionen hund v) sowie vordefinierte Literale verwenden, um die Verwendung von Leerzeichen als Trennzeichen zu vermeiden: compare [2 4], 2 4hand 2Kh, die alle das Array definieren [2 4]. Ähnliches gilt 2K1vfür einen leeren Stack [2; 4; 1]. Beispiel .

Buchstaben in numerischen Array-Literalen

Bei etwas größeren Zahlen können Sie Leerzeichen sparen, indem Sie die Tatsache ausnutzen, dass einige Buchstaben numerische Bedeutungen in Array-Literalen haben. So kann man stattdessen [3 5 2 7;-4 10 12 5]verwenden [IAHC;dX12A]. Beispiel .

Insbesondere innerhalb von Array-Literalen,

  • O, l, H I KHaben ihre üblichen Bedeutungen 0, ...,4
  • A, ..., Egemein 5, ...,9
  • X meint 10
  • a, ... dgemein -1, ...,-4
  • Jund Gmeine 1jund-1j
  • P meint pi
  • Y meint inf
  • Nbedeutet NaN.

String und aufeinanderfolgende Unterschiede

Bei größeren Zahlen dkann es hilfreich sein , eine Zeichenfolge zu definieren und ihre aufeinander folgenden Unterschiede (mit ) zu berechnen : Anstelle von können [20 10 35 -6]Sie verwenden '!5?b\'d. Dies funktioniert, weil ddie Codepunkte der Zeichen zur Berechnung der Unterschiede verwendet werden. Beispiel .

Luis Mendo
quelle