Tips untuk bermain golf di K

17

K adalah bahasa pemrograman dalam keluarga APL yang dirancang oleh Arthur Whitney. Sementara juru bahasa resmi adalah sumber tertutup dan komersial, versi percobaan dengan batas ruang kerja 32 bit ruang pengalamatan (yang seharusnya tidak menimbulkan masalah untuk kode golf) dapat ditemukan di situs web Sistem Kx . Versi ini dibundel sebagai bagian dari database kdb + secara bahasa dikenal sebagai "K4". Ada juga implementasi K open-source yang tersedia, termasuk Kona , yang didasarkan pada K3, dan penerjemah saya sendiri yang disebut oK , yang didasarkan pada K5 dan memiliki REPL berbasis browser .

Kx Systems memiliki wiki dengan informasi K4 / kdb + / Q, dan halaman Kona GitHub juga memiliki koleksi bahan referensi yang sangat baik . Saya sudah mulai menulis manual untuk oK / k5 yang mungkin menjadi referensi yang berguna.

Seperti J dan APL, K adalah bahasa yang sangat singkat dan kuat, dan sering dapat membuat pertunjukan yang bagus dalam kode golf. Silakan bagikan kiat, trik, dan idiom yang Anda temukan, dan jika Anda belum mencoba K sebelum mempertimbangkan untuk mencobanya! Tolong kirim satu tip per jawaban!

JohnE
sumber

Jawaban:

5

Menyebut angka dua

Dengan asumsi Anda memiliki fungsi diad (argumen 2) f:

f: {x+2*y}

Anda biasanya akan menyebutnya seperti ini:

f[3;47]

Anda dapat menyimpan karakter dengan gulirkan di argumen pertama dan kemudian menerapkan fungsi parsial yang dihasilkan ke argumen kedua dengan penjajaran:

f[3]47

Hal yang sama berlaku untuk pengindeksan array:

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

  z[1;2]
92

  z[1]2
92
JohnE
sumber
5

Mencetak baris baru

Jika output Anda harus memiliki baris baru, Anda mungkin tergoda untuk melakukan ini:

`0:whatever,"\n"

Jangan . K2 (dan kemungkinan versi lainnya) memiliki fitur yang rapi di mana Anda dapat mencetak daftar baris:

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

Jadi, jika Anda perlu menambahkan baris baru ke output, lakukan saja:

`0:,whatever
kirbyfan64sos
sumber
3

Kisaran

Biasanya jika Anda ingin membuat vektor nomor urut yang Anda gunakan !:

  !5
0 1 2 3 4

Jika Anda ingin membuat rentang yang dimulai dari angka selain nol, Anda kemudian akan menambahkan offset ke vektor yang dihasilkan:

  10+!5
10 11 12 13 14

Ada beberapa pendekatan yang tidak biasa yang dapat bekerja lebih baik untuk situasi tertentu. Misalnya, jika basis dan offset Anda sudah menjadi anggota daftar, Anda dapat menggunakan "di mana" dua kali:

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

Untuk urutan yang tumbuh lebih lambat, pertimbangkan untuk menggabungkan "di mana" dengan "ambil":

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

Jika Anda ingin membuat rentang kelipatan, Anda bisa melipatgandakan hasil !atau Anda dapat memindai ( \) daftar salinan ukuran langkah:

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

Jika Anda mencoba menghindari tanda kurung, yang pertama lebih baik jika panjang urutannya variabel dan ukuran langkah tetap, sedangkan yang kedua lebih baik jika ukuran langkah adalah apa yang cenderung bervariasi. Memilih variasi yang tepat dapat menghemat 1 atau 2 karakter. Perbedaan off-by-one juga bisa menguntungkan Anda.

JohnE
sumber
2

Pemain dari string mahal. Cukup gunakan eval. Ini:

0.0$a

dapat menjadi seperti ini:

. a

Di K5, byte lebih pendek:

.a
kirbyfan64sos
sumber
2

Setiap hak

Kadang-kadang Anda mungkin menemukan diri Anda menulis (atau tiba dengan penyederhanaan) ekspresi yang diapit yang diaplikasikan melalui masing-masing-monad:

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

Ini adalah satu karakter yang lebih pendek untuk mengubah pola ini menjadi aplikasi setiap hak:

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

Permutasi Siklik

Dyadic !di K3 / K4 adalah "rotate":

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

Ketika "memindai" ( \) disediakan dengan kata kerja monadik, ia bertindak sebagai operator titik tetap. Dalam K, operator titik tetap berulang kali menerapkan kata kerja mereka ke nilai sampai nilai awal ditinjau kembali atau nilai berhenti berubah. Menggabungkan rotasi dengan pemindaian titik-tetap menyediakan cara yang sangat nyaman untuk menghitung satu set permutasi siklik dari daftar:

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

Anda bisa mencari kari !melalui tanda kurung atau tanda kurung untuk membuat kereta kata kerja (1!):

![1]\
(1!)\

(Catatan yang 1!\memiliki perilaku yang sama sekali berbeda!) Masing-masing memiliki panjang yang sama tetapi yang pertama mungkin lebih diinginkan jika langkah rotasi adalah sesuatu selain 1; dalam hal ini tanda kurung membatasi subekspresi tanda kurung "gratis".

Sebagai contoh, berikut adalah program singkat yang menguji melalui brute force apakah string x berisi substring y (secara siklis!):

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

Hati-hati pengguna K5! K5 telah mengubah arti diad !, jadi teknik ini tidak mudah. Ini akan berfungsi seperti yang diharapkan di Kona.

JohnE
sumber
1

Hindari Persyaratan

K memiliki konstruksi kondisional ( :[) yang setara dengan gaya Lisp cond:

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

Anda dapat memiliki kondisi sebanyak yang Anda suka, dan jika tidak ada yang cocok dengan nilai default dikembalikan.

Kadang-kadang (seperti pada program rekursif atau program yang sebaliknya bergantung pada urutan efek samping), tidak ada jalan untuk menggunakan salah satunya. Namun, dalam situasi di mana Anda mampu melakukan sedikit pekerjaan tambahan, Anda sering dapat mengganti "cond" dengan pengindeksan daftar.

Pertimbangkan program fizzbuzz yang terkenal . Ditulis dengan gaya pemrograman imperatif konvensional, kita dapat menggunakan:

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

Ada sedikit pengulangan di sini di tes keterbagian. Pendekatan yang berbeda mengakui bahwa ada 4 kasus (angka, dapat dibagi dengan hanya 3, dapat dibagi dengan hanya 5, dapat dibagi dengan 3 dan 5) dan upaya untuk secara langsung menghitung indeks yang memilih salah satu kasus ini dari daftar:

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

Dua karakter lebih pendek, dan penggunaan bahasa yang lebih baik. Mengetahui bahwa literal daftar dievaluasi dari kanan ke kiri, kami juga mendapatkan beberapa peluang golf tambahan untuk menggabungkan subekspresi yang digunakan kembali. Kami tidak dapat dengan mudah melakukan ini dalam versi berbasis-cond, karena case string tidak dievaluasi sama sekali jika mereka tidak dipilih:

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

Sekarang kami telah menyimpan 5 karakter secara keseluruhan. Secara kebetulan, contoh khusus ini bekerja lebih baik lagi di k5, karena kita memiliki "paket" berlebihan untuk /menangani langkah mengalikan dengan vektor koefisien dan menjumlahkan:

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

Perhatikan juga bahwa perilaku "find" ( ?), yang menghasilkan indeks melewati akhir daftar kunci jika item tidak ditemukan, secara khusus dirancang untuk mendukung penanganan kasus "default" dalam jenis pengindeksan ini. Pertimbangkan fragmen ini untuk mengonversi vokal menjadi huruf besar:

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

Lawan satu dari:

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

(Saya tahu mana yang saya lebih suka baca juga!)

JohnE
sumber