Suggerimenti per giocare a golf in K


17

K è un linguaggio di programmazione della famiglia APL progettato da Arthur Whitney. Mentre l'interprete ufficiale è a codice chiuso e commerciale, una versione di prova con un limite dell'area di lavoro di 32 bit di spazio di indirizzamento (che non dovrebbe creare problemi per il codice golf) è disponibile sul sito Web di Kx Systems . Questa versione inclusa nel database kdb + è colloquialmente nota come "K4". Ci sono anche implementazioni K open source disponibili, incluso Kona , che si basa su K3, e il mio interprete chiamato oK , che si basa su K5 e ha un REPL basato su browser .

Kx Systems ha una wiki con informazioni K4 / kdb + / Q e la pagina Kona GitHub ha anche un'eccellente raccolta di materiali di riferimento. Ho iniziato a scrivere un manuale per oK / k5 che potrebbe essere un riferimento utile.

Come J e APL, K è un linguaggio molto conciso e potente, e spesso può fare una buona esibizione nel code golf. Per favore, condividi suggerimenti, trucchi e modi di dire che scopri, e se non hai mai provato K prima di provare a fare un giro! Invia un suggerimento per risposta, per favore!

Risposte:


5

Chiamare una diade

Supponendo che tu avessi una funzione diadica (a 2 argomenti) f:

f: {x+2*y}

Normalmente lo chiameresti così:

f[3;47]

È possibile salvare un carattere invece esaminando il primo argomento e quindi applicando la funzione parziale risultante al secondo argomento mediante la giustapposizione:

f[3]47

Lo stesso vale naturalmente per l'indicizzazione dell'array:

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

  z[1;2]
92

  z[1]2
92

5

Stampa di nuove righe

Se il tuo output deve avere una nuova riga, potresti essere tentato di farlo:

`0:whatever,"\n"

Non farlo . K2 (e probabilmente altre versioni) ha una caratteristica ordinata in cui è possibile stampare un elenco di linee:

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

Quindi, se devi aggiungere una nuova riga all'output, fai semplicemente:

`0:,whatever

3

Intervalli

Normalmente se vuoi creare un vettore di numeri sequenziali usi !:

  !5
0 1 2 3 4

Se desideri creare un intervallo che inizia con un numero diverso da zero, aggiungi un offset al vettore risultante:

  10+!5
10 11 12 13 14

Ci sono alcuni approcci insoliti che potrebbero funzionare meglio per una situazione particolare. Ad esempio, se la base e l'offset sono già membri di un elenco, è possibile utilizzare "dove" due volte:

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

Per sequenze a crescita più lenta, considera la combinazione di "where" con "take":

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

Se si desidera creare un intervallo di multipli, è possibile moltiplicare il risultato !o scansionare ( \) un elenco di copie delle dimensioni del passaggio:

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

Se stai cercando di evitare le parentesi, la prima è migliore se la lunghezza della sequenza è variabile e la dimensione del passo è fissa, mentre la seconda è migliore se la dimensione del passo è ciò che tende a variare. La scelta della variazione corretta può salvare 1 o 2 caratteri. La differenza off-by-one potrebbe anche funzionare a tuo favore.


2

I cast delle stringhe sono costosi. Usa solo eval. Questo:

0.0$a

può diventare proprio questo:

. a

In K5, è un byte più breve:

.a

2

Ogni diritto

Occasionalmente potresti trovarti a scrivere (o ad arrivare per semplificazione) un'espressione tra parentesi applicata tramite ciascuna monade:

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

È più breve di un carattere convertire questo modello in un'applicazione di ciascun diritto:

  2#/:3 4 5
(3 3
 4 4
 5 5)

1

Permutazioni cicliche

Dyadic !in K3 / K4 è "ruota":

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

Quando "scan" ( \) viene fornito con un verbo monadico, agisce come un operatore a virgola fissa. In K, gli operatori a virgola fissa applicano ripetutamente il loro verbo a un valore fino a quando il valore iniziale viene rivisitato o il valore smette di cambiare. La combinazione di rotazione con scansione a punto fisso fornisce un modo molto conveniente di calcolare un insieme di permutazioni cicliche di un elenco:

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

Puoi curry ! tra parentesi o parentesi per creare il verbo train (1!):

![1]\
(1!)\

(Nota che 1!\ha un comportamento completamente diverso!) Ognuno di questi ha una lunghezza equivalente ma il primo può essere più desiderabile se il passo di rotazione è diverso da 1; in questo caso le parentesi delimitano una sottoespressione tra parentesi "gratis".

Ad esempio, ecco un breve programma che verifica tramite forza bruta se una stringa x contiene la sottostringa y (ciclicamente!):

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

Gli utenti di K5 attenti! K5 ha cambiato il significato di diadico !, quindi questa tecnica non è così semplice. Funzionerà come previsto a Kona.


1

Evita i condizionali

K ha un costrutto condizionale ( :[) che equivale a uno stile Lisp cond:

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

Puoi avere tutte le condizioni che desideri e se nessuna corrisponde al valore predefinito viene restituito.

A volte (come nei programmi ricorsivi o programmi che altrimenti si basano su una sequenza di effetti collaterali), non è possibile muoversi usando uno di questi. Tuttavia, in situazioni in cui puoi permetterti di fare un po 'di lavoro extra, puoi spesso sostituire un "cond" con l'indicizzazione dell'elenco.

Considera il famigerato programma Fizzbuzz . Scritto in uno stile di programmazione imperativo convenzionale, potremmo andare con:

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

C'è un po 'di ripetizione qui nei test di divisibilità. Un approccio diverso riconosce che ci sono 4 casi (un numero, divisibilità per solo 3, divisibilità per solo 5, divisibilità per 3 e 5) e tenta di calcolare direttamente un indice che sceglie uno di questi casi da un elenco:

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

Due caratteri più brevi e un migliore utilizzo della lingua. Sapendo che i valori letterali dell'elenco vengono valutati da destra a sinistra, otteniamo anche ulteriori opportunità di golf per combinare sottoespressioni riutilizzate. Non avremmo potuto farlo facilmente nella versione basata su cond, poiché i casi di stringhe non vengono affatto valutati se non sono selezionati:

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

Ora abbiamo salvato 5 caratteri in totale. Per inciso, questo esempio particolare funziona ancora meglio in k5, dal momento che abbiamo il sovraccarico "pack" per /gestire la fase di moltiplicazione per un vettore di coefficienti e somma:

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

Si noti inoltre che il comportamento di "find" ( ?), che produce un indice oltre la fine dell'elenco di chiavi se l'elemento non viene trovato, è specificamente progettato per supportare la gestione di un caso "predefinito" in questo tipo di indicizzazione. Considera questo frammento per convertire le vocali in maiuscolo:

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

Contro uno di:

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

(So ​​che preferirei leggere anche io!)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.