GolfScriptはあまりにも頻繁に独自の方法を使用するため、Jでゴルフをするための便利なヒントのリポジトリは、邪悪な帝国との戦いに役立つかもしれないと感じています。この簡潔な言語を短くするためのヒントはありますか?
Jを学習したい人にとっては、jsoftwareサイト、特に語彙、Learning Jガイド、J for Cプログラマーガイドから始めてください。
GolfScriptはあまりにも頻繁に独自の方法を使用するため、Jでゴルフをするための便利なヒントのリポジトリは、邪悪な帝国との戦いに役立つかもしれないと感じています。この簡潔な言語を短くするためのヒントはありますか?
Jを学習したい人にとっては、jsoftwareサイト、特に語彙、Learning Jガイド、J for Cプログラマーガイドから始めてください。
回答:
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^:_
、特にの定義に、u
とv
の周りに再生することができます。同様のケースが条件付きライクu^:(1-v)
vs.にも当てはまります]`u@.v
。特に、名前付き動詞がたくさん浮かんでいる場合は、選択肢を検討してください。また、もう少し柔軟性がありますが、を使用$:
する場合は、簡単にぶつかることのできる再帰の深さがあります。(通常は1800回の反復のようなものですか?)
%&2
すると文字が保存されます」そして-:
別のものを保存します!
Jでゴルフをするときに最も重要なことは、問題を理解するだけでなく、問題を一連の配列変換に減らすことです。Jコードで成功するには、この考え方を理解する必要があります。
たとえば、最近の課題では、最大のサブアレイの問題を解決することが求められました。この問題を解決するストックアルゴリズムは、Kadaneのアルゴリズムが次の非公式な説明を持っていることです。
配列を各位置で調べて、ここで終わる最大の部分配列の合計を見つけます。これは、最大の0または現在のインデックスの値と前の位置で終わる最大の部分配列の合計です。配列全体で最大のサブアレイを見つけるために、これらのサブアレイの最大値を計算します。
命令型コードへの翻訳は簡単です。
このアルゴリズムは、最初は縮小のようには見えない明示的なループがあるため、Jにとっては一見複雑に見えます。アルゴリズムが何をしているのかを理解したら、個々のステップを解き、実際に2つの単純な配列操作を実行することを確認できます。
これで、これら2つのステップはJで非常に簡単に実装できます。翻訳は次のとおりです。
(0 >. +)/\. y , 0
–このステップは、アレイのもう一方の端から動作して、Jのパラダイムにより適合します。0 >. +
は暗黙的です0 >. x + y
。>./ y
まとめると、アルゴリズムの非常に簡潔な実装が得られます。
>./ (0 >. +)/\. y , 0
アルゴリズムの実装にアプローチするこの方法を学ぶと、ソリューションはこのコードと同じくらい簡潔になります。
ここに私が時間をかけて蓄積したいくつかのトリックがあります。このリストは、Jゴルフの知識が増えるにつれて拡張されます。
=
は最初は奇妙ですが、ASCIIアートの課題では非常に役立ちます。&
力の結合が必要な場合は、暗黙のコンテキストでダイアディックを使用します。語彙はu@[&0
、暗黙の代替として示唆しています4 : 'u^:x y
私にので、私もそうです。[:
か@:
のような順序でのu@v
のバリアントを選択することで、u
それは左の引数があります。たとえば、の結果の最初の項目を削除v
する1}.v
には、何らかの理由で[:}.v
ifの代わりに使用}.@v
できない場合を使用します。] v
多くのv@]
場合v
、2進コンテキストでモナドを使用する場合よりも短くなります。これは、特にv
動詞が長い場合に役立ちます。m (n v w) y
代わりに書くことができます(n v m&w) y
。これにより、スペースや括弧を避けることができる場合があります。#\
の代わりに>:@i.@#
。u &. v
v
表側がある場合に便利です。そうでない場合は、代わりに[: vinv u & v
またはを使用できu & (v :. vinv)
ます。^:_
フラッドフィルやシミュレーションなど、収束に到達したいアルゴリズムに非常に役立ちます。=.
と=:
フレーズのどこにでも埋め込むことができます。これを使用して、暗黙の記法では不十分なワンライナーを作成します。,
多次元配列を削減する場合、複数の削減の代わりにモナドを使用します。ループの使用には注意してください。
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)
ます。つまり、と同等です。
入力
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│
└─────┴─────┘
1!:1[2
として(もしあれば)何がうまくいくでしょうか?
2
有効ではないように見えますか?現時点では、試してみるためのJコンピューターはありません。私が見るところ2
ちょうど約ノートの下に、1!:1
それがためです1!:2
。
".
、ランク1-XXであり、,.
常に2次元アレイを生成し、".,' ',.
(空間、ラヴェルとステッチと評価; 8文字)だけで置き換えることができる".,.
(ほつれ項目および評価; 4文字)。
通常、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
。フックはモナドとして適用f
さs
れ、無視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#.inv]
8バイトかかります!別の方法は、文字列に変換し、ランク0 "."0@":
で解析してバイトを節約することですが、さらに良い方法は,.&.":
、別のバイトを保存して、最終コストを8ではなく6バイトにすることです。
私にとって便利ないくつかのことを共有しています。基本的にこれらのすべては私が受け取ったヒントですが、私はほとんどのためのクレジットを持っていません。
+/@:(FGH)
use を使用する代わりに(1#.FGH)
。これは、ベース1にディベースすることを意味し、事実上、配列を合計することを意味します。より長い+/
ですが、キャップやコンポジションは必要ありません+/
。多くの場合、を使用するよりもはるかに短くなります。
ブールリストがあり、後続の真理の数をカウントする場合は、を使用します#.~
。こちらをご覧ください。APLの答えどのようにこの作品の良い説明を提供します。確かに、これは私にとって2回しか役に立ちませんでしたが、とにかく共有したいと思いました。
特定のトリックではなく、単なる一般的な提案:副詞 &.
-underは、多くの場合、エレガントで(より重要な)短い解決策につながります。あなたがゴルフをしているとき、それを覚えておいてください。
多くの場合、それはのために便利です回バイナリ例えば、数から最上位ビットを削除し、このコードおよび他のベース変換の課題:}.&.#:
(二進数のリストに変換し、最初の数字を削除するには、その後、二進数字と変換のリストへの変換を元に戻します10進数に戻ります)。簡単な解決策は、さらに2バイトです#.@}.@#:
。
Underは、を使用できるため、10進数を操作する必要がある場合にも役立ちますu&.":
。たとえば、milesが10進数に分割するための短い方法では、以下を使用します,.&.":
。
最後の例は、ベクトルの大きさを見つける+/&.:*:
ことです:-squareはランク0であるため、*:
-square with &.:
-under からすべての結果を収集する必要があることに注意してください*:
。
時には、のようなコードがあり<"0 i.3 3
、v
rankで動詞を適用したい場合があります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
。
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の後および文字列を含む
本当に文字列をスライスしています。
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
(G~F)~H
純粋な泡の良さです!
&
あなたの友達です、賢く使ってください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
に適用されy
、x
回。
x(v^:)y
is equivalent to
(v^:x)y
&
最も外側の接続詞としてをこれを使用するには、またはのいずれかと同等になるように、定数n
と二項動詞を識別する必要があります。その後、タスク全体を記述または解決できます。この形式は、定数の選択が明白な場合、たとえば3 in (charsをASCII値に変換する)で最も効果的です。u
n u y
y u n
v
n&u
u&n
3 u:
また、の最も外側の構造が接続詞または副詞である場合よりu&n
もわずかに優先されます(この場合は、;n&u
u
n&u
n&(u)
u~&n
代わりに)。
&
dynamicに似た意味で、トレインの任意の場所にダイアディックを配置して、任意の関数を任意の引数に繰り返すことができることに注意してください^:
。
GolfScript gets its own way far too often
2019年に