Golftipps in K

17

K ist eine Programmiersprache der APL-Familie, die von Arthur Whitney entwickelt wurde. Während der offizielle Dolmetscher aus geschlossenen Quellen und kommerziell ist, finden Sie auf der Kx Systems- Website eine Testversion mit einer Arbeitsbereichsbegrenzung von 32 Bit Adressraum (was für Code Golf keine Probleme darstellen sollte) . Diese als Teil der kdb + -Datenbank gebündelte Version wird umgangssprachlich als "K4" bezeichnet. Es gibt auch Open-Source-K-Implementierungen, einschließlich Kona , das auf K3 basiert, und meinem eigenen Interpreter namens OK , der auf K5 basiert und einen browserbasierten REPL hat .

Kx Systems hat ein Wiki mit K4 / kdb + / Q-Informationen und die Kona GitHub-Seite hat auch eine ausgezeichnete Sammlung von Referenzmaterialien. Ich habe begonnen, ein Handbuch für OK / K5 zu schreiben, das eine nützliche Referenz sein kann.

Wie J und APL ist K eine sehr knappe und mächtige Sprache und kann sich im Codegolf oft gut behaupten. Bitte teilen Sie Tipps, Tricks und Redewendungen mit, die Sie entdecken, und falls Sie K noch nicht ausprobiert haben, versuchen Sie es noch einmal! Schreibe einen Tipp pro Antwort, bitte!

JohnE
quelle

Antworten:

5

Einen Dyaden anrufen

Angenommen, Sie hatten eine dyadische (2-Argument) Funktion f:

f: {x+2*y}

Sie würden es normalerweise so nennen:

f[3;47]

Sie können ein Zeichen speichern, indem Sie stattdessen das erste Argument eingeben und die resultierende Teilfunktion durch Nebeneinanderstellen auf das zweite Argument anwenden:

f[3]47

Dasselbe gilt natürlich auch für die Array-Indizierung:

  z: (12 17 98;90 91 92)
(12 17 98
 90 91 92)

  z[1;2]
92

  z[1]2
92
JohnE
quelle
5

Zeilenumbrüche drucken

Wenn Ihre Ausgabe einen Zeilenvorschub haben muss , könnten Sie versucht sein, dies zu tun:

`0:whatever,"\n"

Nicht . K2 (und wahrscheinlich auch andere Versionen) hat eine nette Funktion, mit der Sie eine Liste von Zeilen drucken können:

  `0:("abc";"def")
abc
def

Wenn Sie also eine neue Zeile an die Ausgabe anhängen müssen, gehen Sie wie folgt vor:

`0:,whatever
kirbyfan64sos
quelle
3

Bereiche

Normalerweise verwenden Sie Folgendes, wenn Sie einen Vektor aus fortlaufenden Zahlen erstellen möchten !:

  !5
0 1 2 3 4

Wenn Sie einen Bereich erstellen möchten, der mit einer anderen Zahl als Null beginnt, fügen Sie dem resultierenden Vektor einen Offset hinzu:

  10+!5
10 11 12 13 14

Es gibt einige ungewöhnliche Ansätze, die für eine bestimmte Situation besser funktionieren könnten. Wenn Ihre Basis und Ihr Offset beispielsweise bereits Mitglieder einer Liste sind, können Sie "where" zweimal verwenden:

  &10 5
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1
  &&10 5
10 11 12 13 14

Für langsamer wachsende Sequenzen sollten Sie "where" mit "take" kombinieren:

  5#2
2 2 2 2 2
  &5#2
0 0 1 1 2 2 3 3 4 4

Wenn Sie einen Bereich von Vielfachen erstellen möchten, können Sie das Ergebnis multiplizieren !oder \eine Liste von Kopien mit der Schrittgröße scannen ( ):

  2*!5
0 2 4 6 8
  +\5#2
2 4 6 8 10

Wenn Sie versuchen, Klammern zu vermeiden, ist erstere besser, wenn die Länge der Sequenz variabel und die Schrittgröße fest ist, während letztere besser ist, wenn die Schrittgröße dazu neigt, zu variieren. Durch Auswahl der richtigen Variante können 1 oder 2 Zeichen gespeichert werden. Der Unterschied von eins zu eins könnte auch zu Ihren Gunsten wirken.

JohnE
quelle
2

Abgüsse von Streichern sind teuer. Verwenden Sie einfach eval. Dies:

0.0$a

kann genau das werden:

. a

In K5 ist es ein Byte kürzer:

.a
kirbyfan64sos
quelle
2

Jedes Recht

Gelegentlich stellen Sie möglicherweise fest, dass Sie einen in Klammern gesetzten Ausdruck schreiben (oder zur Vereinfachung kommen), der über jede Monade angewendet wird:

  (2#)'3 4 5
(3 3
 4 4
 5 5)

Es ist ein Zeichen kürzer, um dieses Muster in eine Rechtsanwendung zu konvertieren:

  2#/:3 4 5
(3 3
 4 4
 5 5)
JohnE
quelle
1

Zyklische Permutationen

Dyadisch !in K3 / K4 ist "drehen":

  2!"abcd"
"cdab"
  -1!"abcd"
"dabc"

Wenn "scan" ( \) mit einem monadischen Verb versehen ist, fungiert es als Festkommaoperator. In K wenden Festkommaoperatoren ihr Verb wiederholt auf einen Wert an, bis der Anfangswert erneut angezeigt wird oder sich der Wert nicht mehr ändert. Das Kombinieren von Drehen mit Festkomma-Scan bietet eine sehr bequeme Möglichkeit, eine Reihe von zyklischen Permutationen einer Liste zu berechnen:

  ![1]\1 2 4 8
(1 2 4 8
 2 4 8 1
 4 8 1 2
 8 1 2 4)

Sie können entweder in !Klammern oder in Klammern curry , um das Verb train zu erstellen (1!):

![1]\
(1!)\

(Beachten Sie, dass dies 1!\ein völlig anderes Verhalten hat!) Jedes von diesen hat die gleiche Länge, aber das erstere kann wünschenswerter sein, wenn der Rotationsschritt etwas anderes als 1 ist; In diesem Fall begrenzen die Klammern einen in Klammern gesetzten Unterausdruck "frei".

Als Beispiel ist hier ein kurzes Programm, das mittels Brute Force testet, ob ein String x die Unterzeichenfolge y enthält (zyklisch!):

{|/(y~(#y)#)'![1]\x}

K5 Benutzer aufgepasst! K5 hat die Bedeutung von dyadic geändert !, daher ist diese Technik nicht so einfach. Es wird wie erwartet in Kona funktionieren.

JohnE
quelle
1

Vermeiden Sie Bedingungen

K hat ein bedingtes Konstrukt ( :[), das einem Lisp-Stil entspricht cond:

:[cond1;result1; cond2;result2; cond3;result3; default]

Sie können beliebig viele Bedingungen festlegen. Wenn keine übereinstimmt, wird der Standardwert zurückgegeben.

Manchmal (wie bei rekursiven Programmen oder Programmen, die ansonsten auf einer Abfolge von Nebenwirkungen beruhen) kommt man mit diesen nicht herum. In Situationen, in denen Sie sich zusätzliche Arbeit leisten können, können Sie häufig ein "cond" durch eine Listenindizierung ersetzen.

Betrachten Sie das berüchtigte Fizzbuzz- Programm. Geschrieben in einem konventionellen imperativen Programmierstil, könnten wir gehen mit:

{:[~x!15;"FizzBuzz";~x!3;"Fizz";~x!5;"Buzz";x]}'1+!100

Bei den Teilbarkeitstests gibt es hier einige Wiederholungen. Ein anderer Ansatz erkennt, dass es 4 Fälle gibt (eine Zahl, Teilbarkeit durch nur 3, Teilbarkeit durch nur 5, Teilbarkeit durch 3 und 5) und versucht, einen Index direkt zu berechnen, der einen dieser Fälle aus einer Liste auswählt:

{(x;"Fizz";"Buzz";"FizzBuzz")@+/1 2*~x!/:3 5}'1+!100

Zwei Zeichen kürzer und eine bessere Verwendung der Sprache. Wenn wir wissen, dass Listenliterale von rechts nach links ausgewertet werden, erhalten wir auch einige zusätzliche Möglichkeiten zum Kombinieren wiederverwendeter Unterausdrücke. Dies war in der Cond-basierten Version nicht einfach möglich, da die String-Cases überhaupt nicht ausgewertet werden, wenn sie nicht ausgewählt sind:

{(x;4#t;4_ t;t:"FizzBuzz")@+/1 2*~x!/:3 5}'1+!100

Jetzt haben wir insgesamt 5 Zeichen gespeichert. Übrigens funktioniert dieses Beispiel in k5 noch besser, da wir die "Pack" -Überladung haben /, um den Schritt des Multiplizierens mit einem Koeffizientenvektor und des Summierens zu bewältigen:

{(x;4_t;4#t;t:"FizzBuzz")@2 2/~3 5!\:x}'1+!100

Beachten Sie auch, dass das Verhalten von "find" ( ?), das einen Index nach dem Ende der Schlüsselliste erzeugt, wenn das Element nicht gefunden wird, speziell für die Behandlung eines "Standard" -Falls bei dieser Art der Indizierung entwickelt wurde. Betrachten Sie dieses Fragment, um Vokale in Großbuchstaben umzuwandeln:

{("AEIOU",x)"aeiou"?x}'

Gegen einen von:

{t:"aeiou"?x;:[t<5;"AEIOU"t;x]}'
{:[~4<t:"aeiou"?x;"AEIOU"t;x]}'

(Ich weiß, was ich auch lieber lesen würde!)

JohnE
quelle