Jでのゴルフのヒント


33

GolfScriptはあまりにも頻繁に独自の方法を使用するため、Jでゴルフをするための便利なヒントのリポジトリは、邪悪な帝国との戦いに役立つかもしれないと感じています。この簡潔な言語を短くするためのヒントはありますか?

Jを学習したい人にとっては、jsoftwareサイト、特に語彙Learning Jガイド、J for Cプログラマーガイドから始めてください。


1
読み込みについて何か面白いがあるGolfScript gets its own way far too often2019年に
関係のない文字列の

回答:


14

Jの最後の数文字を絞り出すには、いくつかの微妙な点があります。以下では、各大文字が原始動詞であると仮定します(つまり、名前を区切るために必要なスペースを削除します)。

  • あなたは行きの列車を持っている、とあなたは介して別の途中の上に関数を適用、する必要がある場合([:FLGR)(LF@:GR)同じ文字数を持っていますが、(LF@GR)1が保存されます。GのフレームがFのモナドランク以上である場合、これは有効な変換です。特に、すべての列車には、, ,. ,: ~. /: \: [ ]およびのほとんどの用途と同様に無限のランクが#あり|.ます。

  • リストから文字列を選択する必要があり、これらの文字列にスペースがない場合は、を使用します>i{ab`cd`ef。汚れていますが、新しい文字列ごとに文字を保存します。単一の文字を引っ張っている場合を除き、文字リストは短くするために長さ4でなければなりません。何が起こっているかというと、未定義の名前は動詞への参照として扱われ、それらの動詞の動詞を取ると、名前のボックス化された文字列を取得します。タイプnoun、副詞、または接続詞を持つように既に定義されている名前は、この方法で使用することはできません`

  • 暗黙の動詞だけでなく、式を使用できるほど幸運な場合は、名詞、動詞、副詞など、変数に再利用するビットを割り当てることはほとんど常に価値があります。かっこは、以前にスペースがあった場所にぴったりと収まることで自分自身を返すことがあります。そのような定義のほとんどは、もう一度再利用すれば価値があります。

  • のような接続詞(FGH)^:(u`v`w)は書き直すことができますu`v`w(FGH^:)。これは、1であっても任意の長さの列車で機能しますが、このトリックが正しい引数からかっこを削除する場合にのみ何でも保存できます。このトリックは、左オペランドをプリロードする場合にのみ機能します。(何が起きたのかわからない場合は、「暗黙の副詞」を調べて、J辞書の解析と実行のセクションを調べてください。)

  • 使用しないでくださいa.&i.、使用u:{&a.3&u:が、長さに相当し、前者は(組み合わせに応じて)関連してより有用であるかもしれません。

  • 物事は好き(2%~F)(F%2:)長さは同じです。列車の残りの部分がどのように見えるかに応じて@、最初のポイントで書かれたトリックを使って再構築して、必死なキャラクターを救うことができる場合があるので、これは便利です。(そしてもちろん、場合Fです]と、列車はモナドで、使用して%&2当たり前、文字が保存されます。)

  • 左端の動詞を含む、]または[左動詞としてのフックのような列車(]FGH)

    • ]ダイアディックアプリケーションを分割し、正しい引数のみを使用できます。(左にスワッピングすると(]FGH)~、少なくとも1文字のペナルティがあります。おそらくそれ以上です。)チャーを保存し、(FGH)@]動名詞では非常に便利です!
    • [フックを単項的に適用すると、右側で副作用に対して何かを実行してから、引数を再度返すことができます。最も一般的な使用法は1!:2、おそらくジャンクをフォーマットする場合です。
  • I / Oがひどい。できる限りすべてのループを作成して、プロセスを高速化します。1!:1ランクを持っている0、との両方の1!:2 3ランクを持っているが_ 0、例えば、その1秒のアレイを作製することによって、これを利用して実行し1!:1、それらの上に直接。ご了承ください".ランク1も持っている。したがって、通常はそれをの直後に置くことができ、シェナンガンを1!:1介して付け@たり、ランク付けする必要はありません。

  • これを置く場所を見つけるのは簡単ではありませんが、 ::が、便利です。

    • ::]^:_たとえば、特に強力な組み合わせです。これにより、それ以上できなくなるまで危険なことを行うことができます。(通常の対象^:_ -as-a-a-loopの警告に従います。)

    • また、これにより{、目的のインデックスがないリストでも使用できます。これが発生すると、ドメインエラーがスローされるためです。たとえば、存在する場合にのみリストの先頭を取得するのに役立ちます(::]空のリスト::_1:を返す、またはエラーコードを返すなどを使用してみてください)。

  • ]`($:@u)@.v通常よりも短くすることができu^:v^:_、特にの定義に、uvの周りに再生することができます。同様のケースが条件付きライクu^:(1-v)vs.にも当てはまります]`u@.v。特に、名前付き動詞がたくさん浮かんでいる場合は、選択肢を検討してください。また、もう少し柔軟性がありますが、を使用$:する場合は、簡単にぶつかることのできる再帰の深さがあります。(通常は1800回の反復のようなものですか?)


不利なトリックは本当にクールです。
-FUZxxl

「必死のキャラクターをいくつか保存してください」あなたが照明を勉強しているとき、すべてが移された小言のように見えます!:)
Soham Chowdhury

1
「使用%&2すると文字が保存されます」そして-:別のものを保存します!
リン

11

Jでゴルフをするときに最も重要なことは、問題を理解するだけでなく、問題を一連の配列変換に減らすことです。Jコードで成功するには、この考え方を理解する必要があります。

たとえば、最近の課題では、最大のサブアレイの問題を解決することが求められましたこの問題を解決するストックアルゴリズムは、Kadaneのアルゴリズムが次の非公式な説明を持っていることです。

配列を各位置で調べて、ここで終わる最大の部分配列の合計を見つけます。これは、最大の0または現在のインデックスの値と前の位置で終わる最大の部分配列の合計です。配列全体で最大のサブアレイを見つけるために、これらのサブアレイの最大値を計算します。

命令型コードへの翻訳は簡単です。

  1. Aを入力配列とします。
  2. hmi ←0。
  3. もし iが ≥LEN(A)リターン M
  4. h ←max(0、h + A [ i ])。
  5. m ←max(mh)。
  6. ii + 1。
  7. 後藤 3。

このアルゴリズムは、最初は縮小のようには見えない明示的なループがあるため、Jにとっては一見複雑に見えます。アルゴリズムが何をしているのかを理解したら、個々のステップを解き、実際に2つの単純な配列操作を実行することを確認できます。

  1. 配列をスキャンして、各インデックスで終わる最大の部分配列の長さを計算します。
  2. max関数を使用してこれらの長さを減らし、最大値を見つけます。

これで、これら2つのステップはJで非常に簡単に実装できます。翻訳は次のとおりです。

  1. (0 >. +)/\. y , 0–このステップは、アレイのもう一方の端から動作して、Jのパラダイムにより適合します。0 >. +は暗黙的です0 >. x + y
  2. >./ y

まとめると、アルゴリズムの非常に簡潔な実装が得られます。

>./ (0 >. +)/\. y , 0

アルゴリズムの実装にアプローチするこの方法を学ぶと、ソリューションはこのコードと同じくらい簡潔になります。

ここに私が時間をかけて蓄積したいくつかのトリックがあります。このリストは、Jゴルフの知識が増えるにつれて拡張されます。

  • 辞書を学ぶ。それは本当にあいまいな動詞をたくさん含んでいますが、それらがどれほど有用であるかを理解するまで意味がありません。たとえば、モナド=は最初は奇妙ですが、ASCIIアートの課題では非常に役立ちます。
  • &力の結合が必要な場合は、暗黙のコンテキストでダイアディックを使用します。語彙はu@[&0、暗黙の代替として示唆しています4 : 'u^:x y私にので、私もそうです。
  • 多くの場合、あなたは避けることができる[:@:のような順序でのu@vのバリアントを選択することで、uそれは左の引数があります。たとえば、の結果の最初の項目を削除vする1}.vには、何らかの理由で[:}.vifの代わりに使用}.@vできない場合を使用します。
  • ] v多くのv@]場合v、2進コンテキストでモナドを使用する場合よりも短くなります。これは、特にv動詞が長い場合に役立ちます。
  • 時にはのm (n v w) y代わりに書くことができます(n v m&w) y。これにより、スペースや括弧を避けることができる場合があります。
  • #\の代わりに>:@i.@#
  • u &. vv表側がある場合に便利です。そうでない場合は、代わりに[: vinv u & vまたはを使用できu & (v :. vinv)ます。
  • ランクとその使用方法を理解します。適切なものが得られるまで、ランク接続詞をいじってみてください。ランクがコードに与える影響を理解するのに役立ちます。
  • ^:_ フラッドフィルやシミュレーションなど、収束に到達したいアルゴリズムに非常に役立ちます。
  • 標準ライブラリを知ってください。たくさんの文字を保存する非常に便利な機能が含まれています。
  • copulæ =.=:フレーズのどこにでも埋め込むことができます。これを使用して、暗黙の記法では不十分なワンライナーを作成します。
  • ,多次元配列を削減する場合、複数の削減の代わりにモナドを使用します。
  • チャレンジがランタイム境界を課す場合、特別なコードによってサポートされるフレーズを理解します。いくつかの有用なものは、O(n 2の代わりにO(n)で動作します)反直感。
  • ボックスは木に便利です。

Jは、再利用された計算をキャッシュすることでO(n)でmaxサブアレイソリューションを実行するのに十分スマートですか?
ジョナ

@ジョナ私はそれが二次時間で実行すると思います。
FUZxxl

10

ループの使用には注意してください。

Jにはループ構造(for. do. end.while. do. end.およびバリエーション)がありますが、それらを使用していることに気付いた場合、アルゴリズムがJのゴルフの強さでプレイしていない可能性があり、キャラクターを節約する可能性があります。

^:力の接続詞はあなたの友人です。動詞x回を実行するには:

verb^:x

リスト内の各反復の結果が必要な場合:

verb^:(i.x)

を使用^:して、条件付きで動詞を実行することもできます。

  +:^:(3<])"0[ 1 2 3 4 5 6
1 2 3 8 10 12

アイテムが3より大きい+:場合^:はダブル3<]"0一度にアイテムが機能するように動詞のランクが変更されます)。


ボックス化された値は(i.x)例のように動作f^:(<x)f^:(i.x)ます。つまり、と同等です。
FireFly 14

9

入力

1!:1[1 Enterキーを押すと、1行の入力が終了します。

1!:1[3 入力の行を数行取ります(MacではCtrl-D、WindowsではCtrl-Cで終了します)。

数字を入力しようとしている場合、using ".は文字列を評価し、操作可能な数字のリストを返します。1つの数字を入力しているが、数字を個別に操作する必要がある場合".,.(これに対するJan Dvorakのコメントのおかげ)、または"."0文字列を別々の数字に分割します。

   "."0[1!:1[1
12345
1 2 3 4 5

   ".,.1!:1[1
12345
1 2 3 4 5

文字列を読んでいる場合、個別の文字列のボックス化されたリストを取得する最短の方法はを使用すること;:です。これは、スペースで区切られた文字列に最適です。

   ;:1!:1[1
hello world
┌─────┬─────┐
│hello│world│
└─────┴─────┘

好奇心から、(私はJと少しだけ遊んだことがあります)何1!:1[2として(もしあれば)何がうまくいくでしょうか?
ガフィ

1!:ページで収集できるもの(私はJの専門家ではありません)2は画面なので、画面からの入力はあまり意味がありません。
ガレス

リンクをありがとう。そこから、実際には2有効ではないように見えますか?現時点では、試してみるためのJコンピューターはありません。私が見るところ2ちょうど約ノートの下に、1!:1それがためです1!:2
ガフィ

@Gaffi入力と出力のファイル番号は連続しているように見えるので、これらは固定されており、2、4、および5は出力の下にのみ表示されると推測しています。同じことが1と3についても逆になります。
Gareth

以来".、ランク1-XXであり、,.常に2次元アレイを生成し、".,' ',.(空間、ラヴェルとステッチと評価; 8文字)だけで置き換えることができる".,.(ほつれ項目および評価; 4文字)。
ジョンドヴォルザーク

6

反復を使用してシーケンスを計算する

通常、OEISシーケンスチャレンジを解決するには、そのページに記載されている式のいずれかを使用する必要があります。これらのいくつかはJによく適合し、他はそれほど適合しません。再帰式は単純ですが、反復は簡単ではない場合があります。私が使い始めたパターンは

(s(]f)^:[~]) n
          ]  Gets n
 s           The first value in the sequence
         ~   Commute the argument order, n is LHS and s is RHS
        [    Gets n
      ^:     Nest n times with an initial argument s
  (]f)         Compute f s
             Returns (f^n) s

ここsで、シーケンスの最初の値は、f前の用語が与えられると次の用語を計算する動詞であり、計算する用語nのゼロベースのインデックスです。この方法は、ダイアドのパワーを計算するときに、LHSがダイアドにバインドされて新しいモナドを形成し、そのモナドが初期値にネストされるという事実に依存しています。力副詞に与えられるダイアドはフックで(]f)ありn、LHS のインデックスとシーケンスの用語の値が与えられますs。フックはモナドとして適用fsれ、無視nして結果を返しますf sます。

標準ライブラリ

Jが標準ライブラリで動詞をサポートしていることがあります。たとえば、ほとんどのビット単位の整数演算は、プリミティブコールを使用するよりも短い名前にバインドされています。

AND =: (17 b.) NB. it is actually '$:/ :(17 b.)'

日付と時刻の組み込みも使用できます。

範囲

値のセットが[a, b, c]あり[0, 1, 2, ..., a*b*c-1]、のような製品に基づいて範囲を形成する場合、一般的なアプローチは製品を見つけてから、[:i.*/6バイトかかる範囲を形成することです。短い方法は,@i.4バイトのi.場合です。カウントアップしながら多次元配列を形成でき、フラット化すると同等の範囲が生成されるためです。

連続印刷

明示的なループなしで値を出力して使用し続ける暗黙の方法は([echo)、モナドの場合です。インタープリターで使用されるのと同じ形式でechoその内容を出力する標準ライブラリーの動詞stdoutです。フックは左を使用して同じ入力値を渡します[動詞ます。

10桁の整数

整数の基数10桁を取得する標準的な方法は、10#.inv]8バイトかかります!別の方法は、文字列に変換し、ランク0 "."0@":で解析してバイトを節約することですが、さらに良い方法は,.&.":、別のバイトを保存して、最終コストを8ではなく6バイトにすることです。


5

暗黙の動詞を書く代わりに、明示的な定義の使用を検討してください。必ず3 :''5バイトの費用がかかりますが、あなたはたくさんの節約することができ@@:かつ[:そのように。


5

私が見たいくつかの(かなり)一般的なトリック

私にとって便利ないくつかのことを共有しています。基本的にこれらのすべては私が受け取ったヒントですが、私はほとんどのためのクレジットを持っていません。

ランク1配列の合計

+/@:(FGH)use を使用する代わりに(1#.FGH)。これは、ベース1にディベースすることを意味し、事実上、配列を合計することを意味します。より長い+/ですが、キャップやコンポジションは必要ありません+/。多くの場合、を使用するよりもはるかに短くなります。

末尾の真実を数える

ブールリストがあり、後続の真理の数をカウントする場合は、を使用します#.~こちらをご覧くださいAPLの答えどのようにこの作品の良い説明を提供します。確かに、これは私にとって2回しか役に立ちませんでしたが、とにかく共有したいと思いました。

下 (&。)

特定のトリックではなく、単なる一般的な提案:副詞 &. -underは、多くの場合、エレガントで(より重要な)短い解決策につながります。あなたがゴルフをしているとき、それを覚えておいてください。

多くの場合、それはのために便利です回例えば、数から最上位ビットを削除し、このコードおよび他のベース変換の課題:}.&.#:(二進数のリストに変換し、最初の数字を削除するには、その後、二進数字と変換のリストへの変換を元に戻します10進数に戻ります)。簡単な解決策は、さらに2バイトです#.@}.@#:

Underは、を使用できるため、10進数を操作する必要がある場合にも役立ちますu&.":。たとえば、milesが10進数に分割するための短い方法では、以下を使用します,.&.":

最後の例は、ベクトルの大きさを見つける+/&.:*:ことです:-squareはランク0であるため、*:-square with &.:-under からすべての結果を収集する必要があることに注意してください*:


4

ランクを混乱させるより短い方法

時には、のようなコードがあり<"0 i.3 3vrankで動詞を適用したい場合がありますr。ただし、名詞(など0)を使用する場合、多くの場合、スペースを含める必要があります。これを回避するには、u同等のランクの別の動詞を使用してu"v代わりに使用できます。たとえば、+ランク0 0 0があるため、の<"+代わりに使用できます<"0

以下は、すべての動詞とそのランクの表です(を使用して取得できますv b. 0)。

0 0 0     > + * - % ^ | ! ? <. <: >. >: +. +: *. *: %: ^. j. o. q: r.
0 _ _     -. -: E. i: p:
1 0 1     p..
1 0 _     { A.
1 1 0     p.
1 1 1     #.
1 1 _     C.
1 _ _     ;: ". i. I.
2 _ 2     %.
_ 0 0     = < ~. ~: {: }: ?. L.
_ 1 0     #:
_ 1 _     $ # |. |: {. }. ": {::
_ _ _     , ; [ ] _: $. $: ,. ,: /: \: [: e. s: u: x: 0:

この表を使用するrには、左側で目的のランクを見つけてvから、右側から適切な動詞を選択します。たとえば、verb vをdepth 2 _ 2でベクトル化する必要がある場合、そのランクが左側にあり%.、右側から選択します。次に、のv"%.代わりに使用しますv"2 _ 2


3

strings ライブラリ:ゴルフのヒント

文字列ライブラリは、文字列操作で何かを行うのに非常に役立ちます。もちろん、それはかかりますinclude'strings'(Jを考えると非常にコストがかかります)が、時にはメリットを享受できます。

stringreplace

文字列置換を使用して自分自身を見つけますか?それA stringreplace Bが同じであることに注意してくださいB rplc A

実際、これrplcは実装方法です。

   rplc
 stringreplace~

cuts

動詞cutsはこうして提供します:

xでyをカット(接続詞)
文字列(動詞はnをカット)テキスト
  n = _1文字列まで(ただし、文字列を含まない)
  n = 1から文字列まで
  n = _2の後、ただし文字列を含まない
  n = 2の後および文字列を含む

本当に文字列をスライスしています。


3

0から4までの数字を取得する

コードでの数値の使用に制限がある場合:

0 %_:1を無限大で除算します。
1 #_:無限はいくつですか?
2 #_ _:2つの無限。
3 verb:組み込みがあります。
4 dyad:別の組み込み。

10から35までの数字を取得する

基数無限リテラル:11_bb26_bqなど


3

暗黙のプログラミング

基礎

二項動詞

x (F G H) y == (x F y) G (x H y)
x (F G) y == x F (G y)
x ([: G H) y == G (x H y)  NB. G is called monadically

NB. Verbs are grouped from the right by units of 3.
NB. For the following, think like G, I, K are replaced by the results of (x G y) etc.
NB. and then the sentence is run as usual.
x (F G H I J K) y == x (F (G H (I J K))) y
                  == x F ((x G y) H ((x I y) J (x K y)))

NB. Using conjunctions for dyadic verb
x F@G y == F (x G y)  NB. Atop; Same as x ([: F G) y; Consider as golfing alternatives
x F&G y == (G x) F (G y)  NB. Compose; G is applied monadically to both arguments

モナド動詞

(F G H) y == (F y) G (H y)
(G H) y == y G (H y)  NB. Note that this is different from APL
([: G H) y == G (H y)
(F G H I J K) y == (F (G H (I J K))) y
                == y F ((G y) H ((I y) J (K y)))
F@G y == F (G y)

その他

x&F y == x F y
F&y x == x F y
y F~ x == x F y
F~ y == y F y

トリック

(F x) G (H y)

暗黙のソリューション:(G~F)~H; 実際の動詞に応じて、左右の引数を並べ替えてremoveを検討し~ます。

x ((G~F)~H) y
x (G~F)~ (H y)
(H y) (G~F) x
(H y) G~ (F x)
(F x) G (H y)

モナド二項置換

>:y == 1+y
<:y == 1-~y or _1+y
+:y == 2*y
-.y == 1-y
-:y == 2%~y
*:y == 2^~y
#.y == 2#.y
#.inv y == 2#.inv y  NB. #: doesn't work this way
{.y == 0{y
{:y == _1{y
}.y == 1}.y
+/y == 1#.y

1
(G~F)~H純粋な泡の良さです!
ジョナ

2

& あなたの友達です、賢く使ってください

v動詞、n名詞、xそしてy、それぞれ左と右の引数です。

モナド&:紹介~副詞/接続詞の内部に

副詞/接続詞連鎖は左から評価します。だから、私たちが望むときの_2&+/\&.>ように解析するので、のようなものは動作しませ(_2&+)/\&.>_2&(+/\)&.>。この場合、の+/\ように+/\~&_2&.>解析されるため、の左/右を交換するとバイトを節約できます((+/\)~)&_2&.>。これが機能する理由を確認するには:

+/\~&_2 y
is equivalent to
y +/\~ _2
is equivalent to
_2 +/\ y
is equivalent to
_2&(+/\) y

ダイアッド&:繰り返しx回数

左引数xを与える&と、関数はそれをx何回も適用することyを知っていますか?かなりの数の課題から、特定の操作x時間を実行するように求められます。主に次の2つの方法で実現できます。

  • ^:右オペランドなしでべき乗演算子を使用する

操作がある場合はv、その後v^:、左のオペランドが与えられたとき、モナド動詞になると副詞の列車になります。だから、vに適用されyx回。

x(v^:)y
is equivalent to
(v^:x)y
  • ダイアディックを使用する &最も外側の接続詞としてを

これを使用するには、またはのいずれかと同等になるように、定数nと二項動詞を識別する必要があります。その後、タスク全体を記述または解決できます。この形式は、定数の選択が明白な場合、たとえば3 in (charsをASCII値に変換する)で最も効果的です。un u yy u nvn&uu&n3 u:

また、の最も外側の構造が接続詞または副詞である場合よりu&nもわずかに優先されます(この場合は、;n&uun&un&(u)u~&n代わりに)。

&dynamicに似た意味で、トレインの任意の場所にダイアディックを配置して、任意の関数を任意の引数に繰り返すことができることに注意してください^:

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