CJam ist eine GolfScript-inspirierte Stack-basierte Golfsprache, die von PPCG-Anwendern entwickelt wurde .
Also, in Anlehnung an andere sprachspezifische Tipps Fragen:
Welche allgemeinen Tipps haben Sie zum Golfen in CJam? Bitte posten Sie einen Tipp pro Antwort.
Antworten:
Korrigieren Sie das Modulo für negative Zahlen
Es ist oft ärgerlich, dass das Ergebnis der Modulo-Operation das gleiche Vorzeichen hat wie der erste Operand. ZB
-5 3%
gibt-2
statt1
. Meistens möchten Sie Letzteres. Die naive Lösung besteht darin, Modulo anzuwenden, den Divisor einmal hinzuzufügen und Modulo erneut anzuwenden:Aber das ist lang und hässlich. Stattdessen können wir die Tatsache nutzen , dass Array - Indizierung immer modular aufgebaut ist und funktioniert richtig funktioniert mit negativen Indizes. Wir wandeln den Divisor einfach in einen Bereich um und greifen auf Folgendes zu:
Angewandt
-5
ergibt sich dies1
wie erwartet. Und es ist nur ein Byte länger als das eingebaute%
!Wenn der Modul eine Potenz von 2 ist, können Sie ein weiteres Byte mit bitweiser Arihmetik speichern (was auch viel schneller ist). Vergleichen Sie:
Für den Sonderfall kann ein
65536 == 2^16
anderes Byte gespeichert werden, indem das Umbruchverhalten des Zeichentyps ausgenutzt wird:quelle
Verkettete Zeichenbereiche verschieben
Die Zeichenfolge mit allen Ziffern
"0123456789"
kann als geschrieben werdenDie ASCII-Großbuchstaben (
A-Z
) können als gedrückt werdenDadurch wird die Zeichenfolge aller Zeichen bis zu Z generiert , und die ersten 65 (bis zu @ ) werden verworfen .
Alle ASCII-Buchstaben (
A-Za-z
) können als gepusht werdenDas funktioniert wie oben, erstellt dann eine Kopie, konvertiert in Kleinbuchstaben und hängt an.
Aber es gibt einen kürzeren Weg!
Der oft übersehene
^
Operator (symmetrische Unterschiede für Listen) ermöglicht es, die gleichen Bereiche zu erstellen und dabei drei Bytes zu sparen:'[,
Erstellt den Bereich aller ASCII-Zeichen bis Z ,_el
erstellt eine Kopie in Kleinbuchstaben und^
behält nur die Zeichen beider Zeichenfolgen bei, die in einer, jedoch nicht in beiden Zeichenfolgen enthalten sind.Da alle Buchstaben in der ersten Zeichenfolge Großbuchstaben, alle Buchstaben in der zweiten Kleinbuchstaben und alle Nichtbuchstaben in beiden Zeichenfolgen enthalten sind, ergibt sich die Zeichenfolge.
Das RFC-1642-Base64-Alphabet (
A-Za-z0-9+/
) kann mithilfe der oben beschriebenen Methode übertragen und die Nicht-Buchstaben angehängt werden:Eine ebenso kurze Art, diese Saite zu schieben, nutzt ausschließlich symmetrische Unterschiede:
Wie können wir die Zeichenfolge am Anfang finden?
Alle eingesetzten Zeichenbereiche (
A-Z
,a-z
,0-9
,+
,/
) als Symmetriedifferenz des Bereich zu gedrückt werden , die an dem Null - Byte beginnen, nämlich'A,'[,^
,'a,'{,^
,'0,':,^
,'+,',,^
und'/,'0,^
.Daher werden beim Ausführen
:,:^
von"A[a{):+,/0"
die gewünschten Zeichen verschoben, jedoch nicht in der richtigen Reihenfolge.Wie finden wir die richtige Reihenfolge? Brute Force zur Rettung! Das Programm
Durchläuft alle möglichen Permutationen des Strings, wendet
:,:^
das Ergebnis an und vergleicht es mit der gewünschten Ausgabe ( Permalink ).Das Radix-64-Alphabet, das z. B. von crypt (
.-9A-Za-z
) verwendet wird, kann mit der obigen Methode generiert werden:Dies ist die kürzeste mir bekannte Methode.
Da alle Zeichen in der gewünschten Ausgabe in ASCII-Reihenfolge vorliegen, ist ein Durchlaufen der Permutationen nicht erforderlich.
Nicht alle verketteten Zeichenbereiche können mit in der gewünschten Reihenfolge verschoben werden
:,:^
.Zum Beispiel kann der Bereich
0-9A-Za-z;-?
nicht verschoben werden, indem:,:^
eine Permutation von ausgeführt wird"0:A[a{;@"
.Mithilfe des Codes können wir jedoch eine gedrehte Variante der gewünschten Zeichenfolge finden
welches folgendes ausgibt ( permalink ):
Das bedeutet, dass
hat den gleichen Effekt wie
die nur mit einem leeren Stapel ohne vorangestelltes a verwendet werden kann
[
.quelle
Vermeiden Sie {…} {…}?
Angenommen, Sie haben eine Ganzzahl auf dem Stapel. Wenn es ungerade ist, möchten Sie es mit 3 multiplizieren und 1 hinzufügen; ansonsten möchten Sie es durch 2 teilen.
Eine "normale" if / else-Anweisung würde folgendermaßen aussehen:
Die Verwendung von Blöcken ist jedoch normalerweise nicht der richtige Weg, da
{}{}
bereits vier Bytes hinzugefügt werden.?
kann auch verwendet werden, um eines von zwei Elementen auf dem Stapel auszuwählen:Dies ist ein Byte kürzer.
Block-? mit einer leeren if-Anweisung ist immer ein No-Go. Zum Beispiel,
ist zwei Bytes länger als
Wenn Sie stattdessen haben
und die Sache, die Sie überprüfen, ist nicht negative ganze Zahl, die Sie tun können
Die neuen
{}&
und{}|
sind praktisch, aber manchmal problematisch, wenn Sie den Stapel nicht überladen können.Im Fall von
Sie können stattdessen eine temporäre Variable verwenden:
quelle
!)/
undg)/
sind in den Beispielen kürzer.Switch-Anweisungen
CJam hat keine switch-Anweisungen. Verschachtelte if-Anweisungen funktionieren genauso gut, sind aber
{{}{}?}{}?
bereits 12 Byte lang ...Wenn wir die Bedingung in eine kleine, nicht negative Ganzzahl umwandeln können, können wir alle case-Anweisungen in eine durch Trennzeichen getrennte Zeichenfolge umwandeln und das entsprechende Ergebnis auswerten.
Wenn wir beispielsweise ausführen möchten,
code0
wenn die Ganzzahl des Stapels 0 ist ,code1
wenn es 1 ist undcode2
wenn es 2 ist , können wir entweder verwendenoder
oder
S/
teilt den String in["code0" "code1" "code2"]
,=
extrahiert den entsprechenden Chunk und~
wertet den Code aus.Klicken Sie hier , um switch-Anweisungen in Aktion zu sehen.
Schließlich können wir, wie von @ jimmy23013 und @ RetoKoradi vorgeschlagen, den Schalter in einigen Fällen noch weiter verkürzen. Sprich
code0
,code1
undcode2
hat eine Länge L 0 , L 1 und L 2 jeweils.Wenn L 0 = L 1 ≥ L 2
kann stattdessen verwendet werden, wo
L
ist L 0 . Anstatt an einem Trennzeichen zu teilen, teilen Sie/
die Zeichenfolge hier in gleichlange Abschnitte auf.Wenn L 0 ≥ L 1 ≥ L 2 ≥ L 0 - 1 ist ,
kann stattdessen verwendet werden.
>
Entfernt 0, 1 oder 2 Elemente vom Anfang des Strings und3%
extrahiert jedes dritte Element (beginnend mit dem ersten).quelle
"code0code1code2"5/=~
? Scheint mir viel unkomplizierter, und es ist die gleiche Länge.Gemeinsame Array- und String-Werte
Es gibt bestimmte kurze Arrays oder Strings, die hin und wieder auftauchen, z. B. um Grids zu initialisieren. Naiv können diese 4 oder mehr Bytes kosten, daher lohnt es sich, nach Operationen mit integrierten Werten zu suchen, die das gleiche Ergebnis liefern. Insbesondere die Basenumwandlung ist oft nützlich.
[0 1]
kann geschrieben werden als2,
.[1 0]
kann geschrieben werden alsYYb
(dh 2 in binär).[1 1]
kann geschrieben werden alsZYb
(dh 3 in binär).[[0 1] [1 0]]
kann geschrieben werden als2e!
.[LL]
kann geschrieben werden alsSS/
(Aufteilen eines einzelnen Leerzeichens durch Leerzeichen)."\"\""
kann geschrieben werden alsL`
."{}"
kann geschrieben werden als{}s
.Letzteres kann auf Fälle ausgedehnt werden, in denen alle Klammertypen ein anderes Byte speichern sollen:
"[{<()>}]"
kann geschrieben werden als{<()>}a`
."()<>[]{}"
kann geschrieben werden als{<()>}a`$
.Insbesondere der Trick der Basiskonvertierung kann nützlich sein, um einige unklare Fälle zu berücksichtigen, die hin und wieder auftauchen. ZB
[3 2]
wäreE4b
(14 in Basis 4).In noch selteneren Fällen kann der Faktorisierungsoperator
mf
hilfreich sein. ZB[2 7]
istEmf
.Bitte erweitern Sie diese Liste, wenn Sie auf andere Beispiele stoßen.
quelle
Stapel leeren
Wenn Sie nur den gesamten Stapel löschen möchten, schließen Sie ihn in ein Array ein und fügen Sie ihn ein:
Etwas kniffliger ist es, wenn Sie viele Berechnungen durchgeführt haben, aber nur das oberste Stapelelement behalten und alles darunter verwerfen möchten. Der naive Ansatz wäre, das oberste Element in einer Variablen zu speichern, den Stapel zu löschen und die Variable zu verschieben. Es gibt jedoch eine viel kürzere Alternative: Wickeln Sie den Stapel in ein Array und extrahieren Sie das letzte Element:
(Danke an Optimizer, der mir das neulich gezeigt hat.)
Natürlich, wenn es nur zwei Elemente auf dem Stapel gibt,
\;
ist es kürzer.quelle
\;
würde nur das Element unterhalb der TOS platzieren. Meinten Sie;;
?e
und ZehnerpotenzenWie in ach so vielen anderen Sprachen, können Sie schreiben ,
1e3
anstatt1000
in CJam.Dies funktioniert für nicht ganzzahlige Basen und sogar für nicht ganzzahlige Exponenten. Zum Beispiel
1.23e2
schiebt 123,0 und1e.5
schiebt 3,1622776601683795 (Quadratwurzel von 10 ).Was nicht sofort offensichtlich ist,
1e3
ist, dass es sich tatsächlich um zwei Token handelt:1
schiebt die ganze Zahl 1 auf den Stapel.e3
multipliziert es mit 1000 .Warum ist das so wichtig?
Sie können
e<numeric literal>
etwas aufrufen , das sich bereits auf dem Stapel befindet.Sie können
e<numeric literal>
ein Array zuordnen.quelle
Euklidische Normen
Die einfache Methode zur Berechnung der euklidischen Norm eines Vektors, dh der Quadratwurzel aus der Summe der Quadrate seiner Elemente, ist
Es gibt jedoch einen viel kürzeren Weg.
mh
Der Hypotenuse-Operator zieht zwei Ganzzahlen a und b aus dem Stapel und drückt sqrt (a 2 + b 2 ) .Wenn wir einen Vektor x: = [x 1 … x n ] haben, erreicht n> 1 auf dem Stapel
:mh
(durch Hypotenuse reduzieren) Folgendes:Zuerst werden x 1 und x 2 verschoben und
mh
ausgeführt, wobei sqrt (x 1 2 + x 2 2 ) auf dem Stapel verbleibt .Dann wird x 3 gedrückt und
mh
erneut ausgeführt, wobeisqrt (sqrt (x 1 2 + x 2 2 ) 2 + x 3 2 ) = sqrt (x 1 2 + x 2 2 + x 3 2 ) auf dem Stapel verbleibt.
Nachdem x n verarbeitet wurde, verbleibt sqrt (x 1 2 +… x n 2 ) , die euklidische Norm von x .
Wenn n = 1 und x 1 <0 ist , führt der obige Code zu einem falschen Ergebnis.
:mhz
funktioniert bedingungslos. (Danke an @ MartinBüttner für den Hinweis.)Ich habe diesen Trick zum ersten Mal in dieser Antwort verwendet .
quelle
Konvertieren Sie von der Basis n mit einer Liste von Zahlen, die größer als n sind
CJam konvertiert eine Liste in eine Zahl mit der folgenden Formel: A 0 * n l + A 1 * n l-1 + A 2 * n l-2 + A l * N 0 (mit nicht - negativ
n
).n
ist die Basis undl
ist die Listenlänge. Dies bedeutet, dass A i eine beliebige ganze Zahl sein kann, die nicht im Bereich von liegen muss[0,n)
.Einige Beispiele:
0b
extrahiert das letzte Element und wandelt es in eine Ganzzahl um. Funktioniert wieW=i
und speichert ein Byte, wenn es keine Ganzzahl war. Alles andere in der Liste muss jedoch auch in eine Ganzzahl umgewandelt werden können.1b
Gibt die Summe zurück. Funktioniert wie:i:+
und speichert zwei Bytes, wenn es sich nicht um ganze Zahlen handelt. Es funktioniert auch mit leeren Listen, wenn:+
dies nicht der Fall ist.[i{_1&9 32?_@\m2/}16*;]W%:c
konvertiert ein Zeichen in eine Folge von Zeilenenden und Tabulatoren, die mit zurückkonvertiert werden können2bc
. Die Codierungsfunktion ist jedoch nicht einfach in einem Code-Golf-Programm zu spielen. Aber das braucht man normalerweise nicht.Sie können den folgenden Code verwenden, um eine Zeichenfolge in Unicode-Zeichen zu konvertieren, die nicht in 16-Bit-Zeichen vorliegen und die mit zurückkonvertiert werden können
2A#b128b:c
. (Erklärungen werden später hinzugefügt. Oder ich schreibe später eine neue Version.)Die ähnliche Methode funktioniert mit jeder Menge von
n
Ganzzahlen mit unterschiedlichen Werten modn
, wenn Sie eine Möglichkeit finden, die höchstwertige Ziffer zu entfernen.quelle
Verwenden
$
als ternäres ifWenn es Ihnen nichts ausmacht, Speicherplatz zu verlieren, dh nicht verwendete Elemente auf dem Stapel zu belassen, den Sie später löschen
];
,$
kann der Kopieroperator ein praktischer Ersatz für den ternären Operator sein?
.?
Funktioniert gut, wenn Sie es schaffen, die Bedingung zu berechnen, bevor Sie die beiden Elemente zur Auswahl bringen. Meistens hängt die Bedingung jedoch von diesen Elementen ab, und es ist viel natürlicher, wenn sie darüber liegt.Wenn Sie
A B C
auf dem Stapel haben, können Sie ausführenAnstatt von
zu kopieren,
B
wennC
es wahr undA
anders ist.Wenn
C
es sich um einen tatsächlichen Booleschen Wert (0
oder1
) handelt, können Sie ihn ausführenAnstatt von
zu kopieren,
A
wennC
es wahr undB
anders ist.quelle
Karte für verschachtelte Listen
Angenommen, Sie haben eine verschachtelte Liste wie eine Matrix:
Oder eine Reihe von Zeichenfolgen:
Und Sie möchten einen Block auf die verschachtelte Ebene abbilden (dh auf jede Zahl oder jedes Zeichen anwenden). Die naive Lösung ist verschachtelt
%
:Sie können jedoch den inneren Block tatsächlich auf den Stapel schieben und dann verwenden
f%
.f
Ist "map with additional parameter", so wird es%
auf die äußere Liste abgebildet, wobei der Block als zweiter Parameter verwendet wird:Spart zwei Bytes.
Ein weiterer guter Trick
for (i=0; i<5; ++i) for (j=0; j<5; ++j) {...}
istDas äußere
f
wird auf den ersten Bereich abgebildet und liefert den zweiten Bereich als zusätzlichen Parameter. Aber jetzt, wenn Sie esf
erneut verwenden, ist nur das oberste Stapelelement ein Array. Sief
ordnen den inneren Block diesem zu und geben die äußere "Iterationsvariable" als zusätzlichen Parameter an. Dies bedeutet, dass der innere Block miti
und läuftj
auf dem Stapel ausgeführt wird.Dies hat die gleiche Anzahl von Zeichen wie nur das Abbilden eines Blocks auf ein kartesisches Produkt (obwohl das letztere kürzer wird, wenn Sie die Paare als Arrays benötigen):
Der Unterschied besteht darin, dass diese Version eine einzige Reihe von Ergebnissen für alle Paare liefert, während die doppelte
f
liefert eine verschachtelte Liste liefert, die nützlich sein kann, wenn Sie die Ergebnisse in einem Raster speichern möchten, wobei die Iteratorvariablen die Koordinaten sind.Vielen Dank an Dennis, der mir diesen Trick gezeigt hat.
0.6.4 Update
f
und:
sind jetzt immens verbessert worden, indem jeder andere Operator, einschließlich sich selbst, übernommen wurde. So können Sie jetzt noch mehr Bytes einsparen. Das Zuordnen eines Operators zu einer verschachtelten Liste wurde jetzt noch kürzer:Dies hilft jedoch nicht wirklich beim Zuordnen von Blöcken zu verschachtelten Listen.
Das Anwenden von Blöcken oder Operatoren auf das kartesische Produkt wurde jetzt auch kürzer, sowohl für Blöcke als auch für Operatoren:
Schön ist, dass Sie diese nun verschachteln können. So können Sie einen Operator genauso einfach auf die dritte Ebene einer Liste anwenden:
Oder ein Block mit einigen Tricks:
quelle
f~
...f
erwartet einen binären Operator,~
ist unär; hast du vielleicht wollen:~
? Wir können dies auch im ChatUnhandled char after ':': :
( link )Vektorisierte Operatoren für ASCII-Kunst
Bei vielen ASCII-Kunstherausforderungen ist es nützlich, zwei verschiedene Muster zu generieren, um sie später zu überlagern. Vektorisierte Operatoren können sehr hilfreich sein, um verschiedene Arten von Überlagerungen zu erzielen.
Eine nützliche Eigenschaft der Vektorisierung von Operatoren besteht darin, dass der Operator für jedes Element der kürzeren Zeichenfolge / des kürzeren Arrays nur einmal ausgeführt wird, während die Elemente der größeren Zeichenfolge, die keine Gegenstücke haben, unberührt bleiben.
.e<
Der minimale Operator
e<
für Paare von Zeichenfolgen, Zeichen, Arrays und ganzen Zahlen. es wirft zwei Gegenstände vom Stapel und drückt den unteren auf den Rücken.Da ein Leerzeichen einen niedrigeren Codepunkt als alle anderen druckbaren ASCII-Zeichen hat,
.e<
können Sie Teile eines generierten Musters "löschen":Ein vollständiges Beispiel finden Sie in meiner Antwort auf " Me Want Honeycomb" .
.e>
Der maximale Operator
e>
arbeitet als minimaler Operator, mit dem entgegengesetzten Ergebnis.Auch hier kann aufgrund des niedrigen Codepunkts des Leerzeichens
.e>
ein Muster druckbarer Zeichen in einen Leerzeichenblock eingefügt werden:Ein vollständiges Beispiel finden Sie in meiner Antwort auf Seven Slash Display .
.e&
Der logische AND-Operator
e&
drückt das linke Argument, wenn es falsch ist, und das rechte Argument, wenn es falsch ist.Wenn keines der Muster falsche Elemente enthält, kann dies verwendet werden, um bedingungslos ein Muster über ein anderes zu legen:
Ein vollständiges Beispiel finden Sie in meiner Antwort auf " Drucken der amerikanischen Flagge". .
.e|
Der logische ODER-Operator
e|
kann wie oben beschrieben mit umgekehrter Argumentreihenfolge verwendet werden:quelle
Verwenden Sie
&
diese Option , um zu überprüfen, ob sich ein Element in einer Liste befindetZum
Sie können verwenden
stattdessen wird 0/1 und truthy / falsey zurückgegeben.
quelle
z
und nicht rechteckige ArraysDer zip-Operator
z
transponiert die Zeilen und Spalten eines zweidimensionalen 1- Arrays A , dessen Elemente auch iterabel sein können.Bei nicht rechteckigen Arrays konvertiert CJam im Gegensatz zu den integrierten
zip
Funktionen in Python (schneidet die Zeilen auf die gleiche Länge ab) oder Ruby (nil
füllt die Zeilen mit Pads auf ) einfach die Spalten des Arrays in Zeilen, wobei die Längen und ignoriert werden Lücken.Zum Beispiel das Array komprimieren
entspricht dem Komprimieren des Arrays
oder das Array
wie alle drei Aktionen drücken
auf dem Stapel.
Dies bedeutet zwar, dass
z
es sich nicht um eine Involution handelt (was gelegentlich nützlich wäre), es gibt jedoch einige Anwendungen.Zum Beispiel:
Wir können die Spalten eines Arrays nach oben ausrichten (dh das erste Array in das zweite umwandeln), indem wir zweimal komprimieren:
Kleinere Modifikationen des obigen Verfahrens können für ähnliche Probleme verwendet werden.
Um zum Beispiel die Spalten eines Arrays nach unten auszurichten (dh das zweite Array in das erste zu verwandeln), können wir zweimal in umgekehrter Reihenfolge zippen:
Bei einem gegebenen Array von Zeichenfolgen können wir die Länge der längsten Zeichenfolge folgendermaßen berechnen:
Durch Komprimieren und Berechnen der Anzahl der Zeilen des Ergebnisses können jedoch drei Bytes eingespart werden:
1 Wenn eine der "Zeilen" von A nicht iterierbar ist, werden
z
sie als Singletons behandelt, sodass das Komprimieren für beliebige Arrays funktioniert.quelle
z
Spalten in Zeilen konvertiere, während leere Werte übersprungen werden. Im Beispiel ist die erste Spalte in der Eingabe 1, 2, 3, die zweite Spalte ist 4, 5 (leere Position wird übersprungen) und die dritte Spalte ist 6. Dies sind dann die Zeilen des Ergebnisses.Ausnahmen
Alle Ausnahmen sind in CJam fatal. Da die Ausgabe in STDERR standardmäßig ignoriert wird , können wir dies zu unserem Vorteil nutzen.
Alle Bediener in CJam arbeiten, indem sie null oder mehr Elemente aus dem Stapel entfernen, eine Aufgabe ausführen und null oder mehr Elemente auf den Stapel verschieben. Während die Aufgabe ausgeführt wird, treten Ausnahmen auf, sodass die Elemente weiterhin angezeigt werden, aber nichts zurückgegeben wird.
Hier sind einige Anwendungsfälle:
Einen kleinen Stapel räumen
Zum Löschen eines Stapels, der zwei Elemente enthält,
@
kann verwendet werden.@
versucht, drei Stapelelemente einzufügen, schlägt jedoch nach dem Einfügen des zweiten fehl.Jeder andere Operator, der drei Elemente einblendet, hat denselben Zweck.
Sehen sie in Aktion hier .
Entfernen von zwei oder drei Elementen vom Stapel
Jeder Operator, der für diese bestimmten Elemente nicht implementiert ist, kann verwendet werden, um zwei oder drei Elemente unmittelbar vor dem Beenden aus dem Stapel zu entfernen.
So platzieren Sie zwei Elemente:
b
funktioniert, wenn eines davon ein Zeichen oder keines eine Ganzzahl ist.Das Einfügen von drei Elementen
t
funktioniert, wenn keines der beiden untersten Elemente eine Iteration ist, das unterste Element leer ist oder keines der Elemente eine Ganzzahl ist.Verlassen einer Schleife
Gelegentlich müssen wir eine Schleife verlassen, wenn eine Ganzzahl Null wird oder eine Zeichenfolge zu kurz wird. Anstatt auf diese Bedingungen zu testen, können wir das Programm einfach seinen natürlichen Verlauf lassen, wenn die beteiligten Operationen für Null, die leere Zeichenfolge oder Singletons fehlschlagen.
Ein Beispiel zum Rechnen finden Sie hier .
Ein Beispiel für Zeichenfolgen finden Sie hier .
Bedingte Ausführung
Wenn der Quellcode für bestimmte Eingabetypen nicht ausgeführt werden soll, können wir manchmal einen Operator verwenden, bei dem diese Art von Eingabe fehlschlägt.
Zum Beispiel
i
wird für Strings fehlschlagen , die auf eine ganze Zahl bewerten nicht undew
wird für Strings der Länge 0 oder 1 scheitern.Sehen sie in Aktion hier .
quelle
Max / Min aus einem Array
Hier ist eine für den Anfang!
Wenn Sie die maximale oder minimale Anzahl eines Arrays ermitteln müssen, besteht die einfachste und kleinste Möglichkeit darin, das Array zu sortieren und dann das erste oder letzte Element herauszunehmen.
Also, wenn das Array variabel ist
A
ist das Maximum und
ist das Minimum.
Beides gleichzeitig zu bekommen ist auch möglich
Dies mag nach dem Lesen offensichtlich erscheinen, aber jeder erste Versuch tendiert dazu, das Array zu verwenden
e<
oder es zue>
durchlaufen, was so aussiehtDas ist 2 Bytes länger und noch länger, wenn Sie sowohl max als auch min wollen.
quelle
(
und)
anstelle von0=
und verwendenW=
.:e<
und:e>
Verwenden Sie einen Zeitstempel für große Zahlen
Wenn Sie eine sehr große, aber willkürliche Zahl benötigen, verwenden Sie normalerweise entweder die wissenschaftliche Notation
9e9
oder erhöhen eine der großen eingebauten Variablen auf eine ähnliche Potenz wieKK#
. Wenn es Ihnen jedoch egal ist, wie hoch die tatsächliche Zahl ist, und diese nicht durchgehend gleich sein muss (z. B. als Obergrenze für eine Zufallszahl), können Sie dies in zwei Bytes tunstattdessen. Dies gibt den aktuellen Zeitstempel in Millisekunden an und liegt in der Größenordnung von 10 bis 12
quelle
e9
.Überprüfen Sie, ob zwei Zeichenfolgen / Arrays nicht gleich sind
Manchmal möchten Sie einen Wahrheitswert, wenn zwei Zeichenfolgen oder Arrays nicht gleich sind, und einen falschen Wert, wenn dies der Fall ist. Die naheliegende Lösung sind zwei Bytes:
Auf Gleichheit prüfen und Ergebnis invertieren. Unter bestimmten Bedingungen können Sie jedoch verwenden
Wenn
#
es auf zwei Arrays angewendet wird, sucht es tatsächlich nach dem zweiten Array als Unterarray des ersten Arrays (und gibt den Index an, in dem das Unterarray beginnt). Wenn also die beiden Arrays gleich sind, wird das Subarray gleich zu Beginn gefunden und gibt0
, was falsch ist. Aber wenn das zweite Array nicht gefunden werden kann, wird es geben,-1
was wahr ist.Der Grund, warum wir eine zusätzliche Bedingung für die beiden Arrays benötigen, ist, dass dies auch einen falschen Wert ergibt, wenn das zweite Array ein nicht triviales Präfix des ersten ist, zB:
gibt,
0
obwohl die Saiten nicht gleich sind. Die einfachste Bedingung, die diesen Fall ausschließt, ist, wenn Sie wissen, dass beide Arrays die gleiche Länge haben. In diesem Fall wissen Sie, dass beide Arrays gleich sind, wenn eines dem anderen vorangestellt ist. Unter bestimmten Umständen können jedoch auch schwächere Bedingungen ausreichend sein. Wenn Sie beispielsweise wissen, dass die Zeichenfolgen sortiert sind, ist ein Präfix immer die erste und nicht die zweite Zeichenfolge.quelle
c
und 16-Bit-GanzzahlenUm vorzeichenlose 16-Bit-Ganzzahlen mit korrektem Zeilenumbruch zu addieren (oder zu subtrahieren), können Sie
+65536%
oder verwenden+2G#%
.Jedoch,
ist viel kürzer. Zeichen werden bei 65536 umbrochen , daher hat das Umsetzen auf Character (
c
) und dann auf Long (i
) einen ähnlichen Effekt wie65536%
, mit dem zusätzlichen Vorteil, dass das Ergebnis nicht negativ ist.Mit demselben Trick kann 65535 gedrückt werden :
quelle
Power setzt
Angenommen, Sie haben ein Array und möchten ein Array mit allen möglichen Teilmengen dieses Arrays. Der Trick besteht darin, mit einem leeren Array zu beginnen und dann für jedes Element die bereits vorhandenen Teilmengen zu duplizieren und ihnen das neue Element hinzuzufügen (wobei das vorherige Ergebnis beibehalten wird, in dem das Element nicht hinzugefügt wurde ). Beachten Sie, dass Sie den Stack mit dem Basisfall initialisieren müssen, dh einem Array, das nur ein leeres Array enthält: Das könnte so aussehen:
Das Schöne daran ist, dass Sie sofort eine Berechnung für die Teilmenge ausführen können, möglicherweise ohne zusätzliche Zeichen. Angenommen, Sie möchten die Produkte aller Untergruppen. In diesem Fall ist der Basisfall ein Array, das Folgendes enthält
1
: Bei jedem Schritt nehmen Sie die vorherige Liste möglicher Produkte, duplizieren sie und multiplizieren alles im Duplikat mit dem neuen Element:quelle
Überprüfen Sie, ob die Elemente in einer Liste alle gleich sind
Ich finde das auch erwähnenswert. Verwenden:
Gibt true zurück, wenn nicht alle gleich sind, oder leere Liste, wenn alle gleich sind. Fehler, wenn die Liste leer ist.
Falls das extrahierte Element selbst ein Array (oder eine Zeichenfolge) sein könnte:
Verwenden Sie
!
oder!!
, um boolesche Werte abzurufen. Falls es sich bei dem extrahierten Element möglicherweise um ein Array handelt und es höchstens zwei verschiedene Elemente gibt und Sie möchten, dass es 1 ist, wenn nicht alle gleich sind, ist dies kürzer:quelle
0=
für StreicherUm das erste Element eines Arrays abzurufen, müssen Sie verwenden
0=
(oder(
, wenn Sie nichts dagegen haben, den Rest des Arrays auf dem Stapel zu belassen).Wenn es sich bei diesem Array jedoch um eine Zeichenfolge handelt, ist das Umwandeln in Zeichen ausreichend.
Beispiel
quelle
c
das erste Element eines Arrays extrahieren lässt , was nützlicher und konsistenter wäre.Drehen eines Arrays (oder des Stapels) um eine Einheit nach links
CJam hat den Operator " Links drehen"
m<
, den Sie normalerweise verwenden sollten, um ein Array um eine beliebige Anzahl von Einheiten nach links zu drehen.In einigen Fällen können Sie auch
(+
Folgendes verschieben und anhängen:Das zweite Beispiel hat nicht funktioniert, da das erste Element des Arrays ebenfalls iterierbar ist, also
+
verkettet statt angehängt.Wenn Sie das gedrehte Array auf dem Stapel ablegen möchten, können Sie auch
:\
bedingungslos Folgendes verwenden (durch Austauschen reduzieren):Solange Sie keine Öffnung haben
[
, können Sie mit diesem Trick auch den gesamten Stapel drehen, dh das unterste Stapelelement nach oben bringen:quelle
Liste drucken und Stapel leeren
Nehmen wir an, Ihr Stapel enthält eine Liste von Zeichenfolgen / Zahlen / etc. oben und einige andere zusätzliche Gegenstände darunter. dh
Jetzt möchten Sie nur die letzte Liste drucken, und das tun Sie auch
welche Ausgänge
Das scheint wirklich klug zu sein, wenn wir den Trick zum Löschen des Stapels verwenden und nur die Liste drucken, die mit Leerzeichen verbunden ist (was manchmal nicht die gewünschte Methode zum Drucken einer Liste ist).
Dies kann weiter golfen werden!
Das sind 2 Bytes weniger !
und wenn Sie nur einen anderen Gegenstand als die Liste auf dem Stapel haben, ist er sogar noch kürzer!
Die Schönheit von
p
ist, dass es das oberste Element aus dem Stapel entfernt, es stringifiziert (und am Ende eine neue Zeile hinzufügt) und sofort auf STDOUT druckt, ohne auf die Vervollständigung des Codes zu warten.Der obige Code wird also ausgegeben
Das ist die exakte Darstellung einer Liste, als sie im Stapel war!
quelle
Kartesische Produkte oder alle möglichen Kombinationen von zwei oder mehr Sätzen
CJam hat einen eingebauten kartesischen Produktrechner,
m*
der die beiden obersten Arraylisten / Strings auf einen Stapel legt und daraus alle möglichen Paare erstellt. Zum BeispielBlätter
als der Stapel
Aber was ist, wenn Sie alle möglichen Kombinationen aus mehr als 2 Listen / Zeichenfolgen möchten. Du benutzt
m*
das oft? Zum BeispielLässt das Folgende auf dem Stapel
Beachten Sie, dass es sich bei den Produkten immer noch um Paare handelt, wobei einer der Artikel selbst ein Paar ist. Dies wird nicht erwartet und wir wollen abgeflachte Kombinationen.
Es gibt einen einfachen Weg, das zu tun. Wickeln Sie einfach jede Liste, die Sie für Ihr kartesisches Produkt möchten, in ein Array, erstellen Sie kartesische Produkte paarweise und reduzieren Sie sie jedes Mal:
Diese Blätter
auf stapel.
Möchten Sie die Bestellung beibehalten? Tauschen Sie einfach das Element aus, bevor Sie es wieder zum Array hinzufügen. dh
Willst du nur Permutationen?
Willst du nur einzigartige Elemente in den Kombinationen?
Das war's Leute. für jetzt .
quelle
]:m*:e_
mit einer beliebigen Anzahl von Arrays arbeitenBearbeitung von Saiten
Wenn Sie mit einer komplexen Datenstruktur arbeiten und die darin enthaltenen Elemente einfach sind, kann es manchmal hilfreich sein, sie in Zeichenfolgen zu konvertieren.
Wenn Sie beispielsweise die ersten oder letzten Elemente in einem 2D-Array von Bits abrufen möchten und sich nicht für den zurückgegebenen Typ interessieren,
sA<
ein Byte von0=A<
oder gespeichert:+A<
.Wenn Sie einige Bits in der Eingabe ändern möchten, können Sie die Zeichenfolge vor der Auswertung ändern.
Oder wenn Sie diese Struktur haben und sie in eine einfache Liste konvertieren möchten:
Sie können es mit vielen Charakteren auf andere Weise tun:
Bei Streichern kann es aber auch viel kürzer sein:
Es ist kürzer, auch wenn es Zahlen mit mehr als einer Ziffer haben kann:
Oder:
Wenn Sie kein anderes Array benötigen, das viele solcher Arrays enthält.
quelle
e_
jetzts
noch besser.Verwenden
N
anstelle vonLa
In vielen Fällen benötigen Sie eine Initialisierung für ein Array, das ein leeres Array als einziges Element enthält
La
scheint unnötigerweise 1 Byte länger zu sein.In vielen Fällen müssen Sie vor dem Drucken nach jedem Element eine neue Zeile einfügen, wie z. B.
No
oderN*
. .Wenn beides zutrifft, werden Sie manchmal feststellen, dass Sie das Array nur mit initialisieren können
N
, dessen einziges Element das Newline-Zeichen ist. Stellen Sie sicher, dass Sie den Elementen im Rest Ihres Codes nur Dinge voranstellen. Das erste, was Sie voranstellen müssen, ist immer ein Zeichen oder ein Array. Oder nur anhängen, wenn eine führende Zeile akzeptabel ist und diese dadurch kürzer wird.Funktioniert manchmal
S
auch, wenn Sie die Ausgabe durch Leerzeichen trennen müssen.In seltenen Fällen muss das Anfangselement eine Zeichenfolge sein. Sie können jedoch weiterhin verwenden,
Na
was möglicherweise kürzer ist, als die neue Zeile danach anzuhängen.quelle
Aufteilen bei einem oder mehreren Vorkommen
Angenommen, Sie haben eine Zeichenfolge
"abbcdbbfghbdbb"
und möchten sie aufteilenb
Dies lässt auf Stapel:
Beachten Sie die leeren Zeichenfolgen? Die sind da, weil zwei
b
zusammen waren und nichts dazwischen war. Manchmal möchten Sie dies vermeiden. Sie können dies tun, indem Sieoder leere Zeichenketten herausfiltern
das sind aber 3 extra bytes.
Ein etwas weniger bekannter Operator für diesen speziellen Anwendungsfall ist
%
. Neben tun mod und Karte und Splitting basierend auf der Anzahl ("abcd"2%
="ac"
),%
kann auch aufgeteilt auf Strings / Arrays. Also für den obigen Anwendungsfall:wird verlassen
auf stapel.
Vielen Dank für @ user23013, dass Sie in einer meiner heutigen Antworten darauf hingewiesen haben.
quelle
Verwenden Sie Fold / Reduce als Infix für jeden
Wir haben
:x
als Abkürzung für{x}%
und oder{x}*
(je nachdem obx
unär oder binär). Leider gibt es keinen äquivalenten Infix-Operator zum Kürzen{x}/
. Aber sehr oft , wenn wir tun{x}/
,x
ist eigentlich ein binärer Operator , der wiederholt das Element darunter liegenden auf dem Stapel modifiziert. Wenn dies der Fall ist und das Item kein Array ist, können wir ein Byte speichern, indem wir fold / reduction als foreach missbrauchen:Dies funktioniert, weil beim Falten immer das erste Element unberührt bleibt. Leider wird kein Byte gespeichert, wenn das geänderte Element ein Array ist, da das Hinzufügen es auspacken würde. Aber manchmal haben Sie Glück genug , dass Ihr Array enthält bereits das Element an der Front, in welchem Fall reduce sollte im Auge (statt manuellen Entfernen des Elements vor der Verwendung gehalten werden
{}/
auf dem Rest).quelle
drucken und drucken
CJam hat
print
Betreiber:o
. Es funktioniert, aber der Stapel wird sofort gedruckt, nachdem der gesamte Code ausgeführt wurde. Sie können es stoppen, wenn Sie den Stapel am Ende des Programms löschen. Einfach am Ende setzen:Zum Ausdrucken können Sie
oNo
oder verwendenp
(funktioniert wie`oNo
).quelle
o
undp
.p
Beginnt mit der Konvertierung des zu druckenden Elements in eine eindeutige Zeichenfolgendarstellung.p
ist gleichbedeutend mit der Ausführung`oNo
.