Kでのゴルフのヒント


17

Kは、アーサー・ホイットニーが設計したAPLファミリーのプログラミング言語です。公式の通訳者はクローズドソースで商用ですが、ワークスペースの制限が32ビットのアドレス空間に制限された試用版(コードゴルフでは問題になりません)は、Kx Systemsの Webサイトで見つけることができます。kdb +データベースの一部としてバンドルされているこのバージョンは、通称「K4」と呼ばれています。K3に基づいたKonaや、K5に基づいてブラウザベースのREPLを備えたoKという独自のインタープリターを含む、オープンソースのK実装もあります。

Kx SystemsにはK4 / kdb + / Q情報を含むwikiがあり、Kona GitHubページには優れた参考資料のコレクションもあります。私はoK / k5のマニュアルを書き始めました。これは役に立つリファレンスになるかもしれません。

同様JとAPL、Kは非常に簡潔で強力な言語であり、多くの場合、コードゴルフに示す良いを作ることができます。発見したヒント、トリック、イディオムを共有してください。Kを試していない場合は、試してみてください。回答ごとに1つのヒントを投稿してください。

回答:


5

Dyadを呼び出す

ダイアディック(2引数)関数があると仮定しますf

f: {x+2*y}

通常は次のように呼び出します。

f[3;47]

代わりに、最初の引数をカリー化してから、結果の部分関数を並置によって2番目の引数に適用することにより、文字を保存できます。

f[3]47

同じことが配列のインデックス付けにも自然に機能します。

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

  z[1;2]
92

  z[1]2
92

5

改行を印刷する

出力に改行が必要な場合、これを実行したくなるかもしれません。

`0:whatever,"\n"

しないでください。K2(およびおそらく他のバージョン)には、行のリストを印刷できる便利な機能があります。

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

したがって、出力に改行を追加する必要がある場合は、次のようにします。

`0:,whatever

3

範囲

通常、使用する連続番号のベクトルを作成する場合!

  !5
0 1 2 3 4

ゼロ以外の数で始まる範囲を作成する場合は、結果のベクトルにオフセットを追加します。

  10+!5
10 11 12 13 14

特定の状況によりよく機能する、いくつかの異常なアプローチがあります。たとえば、ベースとオフセットがすでにリストのメンバーである場合、「where」を2回使用できます。

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

成長の遅いシーケンスの場合、「where」と「take」を組み合わせることを検討してください。

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

一定範囲の倍数を作成する場合は、ステップサイズのコピーのリストの結果を乗算する!か、スキャンすることができます(\)。

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

括弧を避けようとする場合、シーケンスの長さが可変でステップサイズが固定されている場合は前者の方が適していますが、ステップサイズが変動する傾向がある場合は後者が適しています。適切なバリエーションを選択すると、1文字または2文字を節約できます。オフ・バイ・ワンの違いもあなたに有利に働く可能性があります。


2

文字列からのキャストは高価です。evalを使用してください。この:

0.0$a

これになります:

. a

K5では、1バイト短くなっています。

.a

2

各権利

ときどき、各モナドを介して適用された括弧で囲まれた式を書いている(または単純化して到着している)ことがあります。

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

このパターンを各権利のアプリケーションに変換するには、1文字短くなります。

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

1

巡回順列

!K3 / K4のダイアディックは「回転」します:

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

"scan"(\)が単項動詞とともに提供される場合、固定小数点演算子として機能します。Kでは、固定小数点演算子は、初期値が再検討されるか、値が変化しなくなるまで、値に動詞を繰り返し適用します。回転を固定小数点スキャンと組み合わせると、リストの循環順列のセットを計算する非常に便利な方法が提供されます。

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

!カッコでカレーするか、括弧で囲んで動詞列を作成できます(1!)

![1]\
(1!)\

1!\完全に異なる動作をしていることに注意してください!)これらはそれぞれ長さが同等ですが、回転ストライドが1以外の場合は前者の方が望ましい場合があります。この場合、括弧は括弧で囲まれた「無料」の部分式を区切ります。

例として、文字列xに部分文字列yが含まれているかどうかを総当たりでテストする短いプログラムを次に示します(周期的に!)

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

K5ユーザーは注意してください!K5はdyadicの意味を変更した!ため、この手法はそれほど簡単ではありません。コナでは期待どおりに動作します。


1

条件付きを避ける

Kには、:[Lispスタイルと同等の条件付き構文()がありますcond

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

必要な数の条件を設定できますが、一致するものがない場合はデフォルト値が返されます。

場合によっては(再帰プログラムや副作用のシーケンスに依存するプログラムのように)、これらのいずれかを使用して回避することはできません。ただし、少し余分な作業を行う余裕がある状況では、「cond」をリストのインデックス付けに置き換えることができます。

悪名高いfizzbuzzプログラムについて考えてみましょう。従来の命令型プログラミングスタイルで記述された場合、次のようになります。

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

分割可能性テストでは、ここでかなりの繰り返しがあります。別のアプローチでは、4つのケース(数、3による可分性、5による可分性、3および5による可分性)が存在することを認識し、これらのケースの1つをリストから選択するインデックスを直接計算しようとします。

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

2文字が短くなり、言語がより適切に使用されます。リストリテラルが右から左に評価されることを知っていると、再利用された部分式を結合するための追加のゴルフの機会も得られます。condベースのバージョンでは、文字列のケースが選択されていない場合はまったく評価されないため、これを簡単に行うことはできませんでした。

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

これで、全体で5文字が保存されました。ちなみに、この特定の例はk5でさらにうまく機能します。これ/は、係数のベクトルを乗算して加算するステップを処理するための「パック」オーバーロードがあるためです。

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

また?、アイテムが見つからない場合にキーリストの末尾を超えるインデックスを生成する「find」()の動作は、この種のインデックス作成で「デフォルト」のケースを処理できるように特別に設計されています。母音を大文字に変換するには、次のフラグメントを検討してください。

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

以下のいずれか:

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

(私はどちらを読みたいかを知っています!)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.