CJamは、PPCGユーザーaditsuによって作成されたGolfScriptにヒントを得たスタックベースのゴルフ言語です。
そのため、他の言語固有のヒントの質問に沿って:
CJamでゴルフをするための一般的なヒントは何ですか?回答ごとに1つのヒントを投稿してください。
CJamは、PPCGユーザーaditsuによって作成されたGolfScriptにヒントを得たスタックベースのゴルフ言語です。
そのため、他の言語固有のヒントの質問に沿って:
CJamでゴルフをするための一般的なヒントは何ですか?回答ごとに1つのヒントを投稿してください。
回答:
モジュロ演算の結果が第1オペランドと同じ符号を与えることはしばしば迷惑です。例えば-5 3%
、の-2
代わりに与える1
。多くの場合、後者が必要です。素朴な修正は、モジュロを適用し、除数を一度追加し、モジュロを再度適用することです:
3%3+3%
しかし、それは長くていです。代わりに、配列のインデックス付けは常にモジュラーであり、負のインデックスで正しく機能するという事実を使用できます。したがって、除数を範囲に変えて、それにアクセスします。
3,=
に適用すると-5
、これは1
予想通りになります。そして、組み込みよりも1バイトだけ長くなってい%
ます!
モジュラスが2のべき乗である場合、ビット単位の算術演算を使用して別のバイトを保存できます(これも非常に高速です)。比較する:
32,=
31&
65536 == 2^16
別のバイトの特殊なケースでは、文字タイプの折り返し動作を利用することで保存できます。
ci
すべての数字を含む文字列"0123456789"
は次のように書くことができます
A,s
大文字のASCII文字(A-Z
)は次のようにプッシュできます。
'[,65>
Zまでのすべての文字のストリングを生成し、最初の65(@まで)を破棄します。
すべてのASCII文字(A-Za-z
)は、次のようにプッシュできます。
'[,65>_el+
上記のように機能し、コピーを作成し、小文字に変換して追加します。
しかし、もっと簡単な方法があります!
次に、見落とされがちな^
演算子(リストの対称差)により、3バイトを節約しながら同じ範囲を作成できます。
'[,_el^
'[,
までのすべてのASCII文字の範囲を作成し、Z、_el
小文字のコピーを作成し、^
1ではなく、両方に表示され、両方の文字列の文字のみを保持します。
最初の文字列のすべての文字は大文字であるため、2番目の文字はすべて小文字であり、すべての非文字は両方の文字列にあり、結果は文字列になります。
RFC 1642 Base64アルファベット(A-Za-z0-9+/
)は、上記の手法を使用して非文字を追加してプッシュできます。
'[,_el^A,s+"+/"+
この文字列をプッシュする同様に短い方法は、対称的な違いのみを使用します。
"+,/0:[a{A0":,:^
最初に文字列を見つけるにはどうすればよいですか?
全て使用する文字の範囲は(A-Z
、a-z
、0-9
、+
、/
)ヌル・バイト、すなわちで開始範囲の対称差としてプッシュすることができ'A,'[,^
、'a,'{,^
、'0,':,^
、'+,',,^
および'/,'0,^
。
したがって、:,:^
on "A[a{):+,/0"
を実行すると、目的の文字がプッシュされますが、正しい順序ではありません。
正しい順序を見つけるにはどうすればいいですか?野Bruな力で救出せよ!プログラム
'[,_el^A,s+"+/"+:T;"0:A[a{+,/0"e!{:,:^T=}=
文字列のすべての可能な順列を反復し:,:^
、結果を適用して、目的の出力と比較します(permalink)。
たとえば、crypt(.-9A-Za-z
)で使用される基数64のアルファベットは、上記の方法を使用して生成できます。
".:A[a{":,:^
これは私が知っている最短の方法です。
目的の出力のすべての文字はASCII順であるため、順列を反復処理する必要はありません。
を使用して、連結されたすべての文字範囲を希望の順序でプッシュできるわけではありません:,:^
。
たとえば、の順列を0-9A-Za-z;-?
実行:,:^
して範囲をプッシュすることはできません"0:A[a{;@"
。
ただし、次のコードを使用して、目的の文字列の回転したバリエーションを見つけることができます
A,'[,_el^'@,59>]s2*:T;"0:A[a{;@"e!{:,:^T\#:I)}=Ip
次を印刷(パーマリンク)します:
10
0:@[a{A;
この意味は
"0:@[a{A;":,:^Am>
と同じ効果があります
A,'[,_el^'@,59>]s
これは、先頭にaを付加せずに空のスタックでのみ使用できます[
。
スタックに整数があると仮定します。奇数の場合は、3を掛けて1を加算します。それ以外の場合は、2で除算します。
「通常の」if / elseステートメントは次のようになります。
_2%{3*)}{2/}?
ただし、{}{}
すでに4バイトが追加されているため、ブロックを使用する方法は通常は使用できません。?
スタック上の2つのアイテムのいずれかを選択するためにも使用できます。
_2%1$3*)@2/?
これは1バイト短くなります。
ブロック-?空のifステートメントは常にノーゴーです。例えば、
{}{2/}?
より2バイト長い
{2/}|
代わりに持っている場合
{2/}{}?
そして、あなたがチェックしているものは非負の整数です、あなたはすることができます
g)/
新しい{}&
と{}|
あなたがスタックを乱雑にすることができない場合に便利な、時には問題があります。
それでも、の場合
_{…}{;}?
代わりに一時変数を使用できます。
:T{T…}&
!)/
そしてg)/
例に短くなっています。
CJamにはswitchステートメントがありません。ステートメントが同様に機能する場合にネストされますが、{{}{}?}{}?
すでに12バイトの長さです...
条件を負でない小さな整数に変換できる場合、区切り文字列のすべてのcaseステートメントを変換し、対応する結果を評価できます。
たとえばcode0
、スタックの整数が0であるcode1
場合、1であるcode2
場合、および2である場合に実行する場合、次のいずれかを使用できます。
_{({code2}{code1}?}{;code0}?
または
[{code0}{code1}{code2}]=~
または
"code0 code1 code2"S/=~
S/
文字列を["code0" "code1" "code2"]
に分割し=
、対応するチャンクを抽出して~
、コードを評価します。
ここをクリックして、実行中のswitchステートメントを確認してください。
最後に、@ jimmy23013と@RetoKoradiが示唆するように、場合によってはスイッチをさらに短くすることができます。言うcode0
、code1
そしてcode2
持っている長さL 0、L 1およびL 2のそれぞれを、。
もしL 0 = L 1 ≥L 2
"code0code1code2"L/=~
代わりに使用することができ、ここL
でL 0。区切り文字で/
分割する代わりに、ここで文字列を等しい長さのチャンクに分割します。
もしL 0 ≥L 1 ≥L 2 ≥L 0 1 -、
"cccooodddeee012">3%~
代わりに使用できます。>
文字列の先頭から0、1、または2つの要素を削除し、3%
3番目ごとに要素を抽出します(最初の要素から開始)。
"code0code1code2"5/=~
ますか?私にはもっと簡単に思えます、そしてそれは同じ長さです。
グリッドを初期化するなど、時々現れる特定の短い配列または文字列があります。単純に、これらは4バイト以上のコストがかかる可能性があるため、同じ結果をもたらす組み込み値の操作を探す価値があります。特に、ベース変換はしばしば有用です。
[0 1]
と書くことができます2,
。[1 0]
として書くことができますYYb
(つまり、バイナリで2)。[1 1]
と書くことができますZYb
(つまり、バイナリで3)。[[0 1] [1 0]]
はと書くことができます2e!
。[LL]
SS/
(単一のスペースをスペースで分割する) と書くことができます。"\"\""
と書くことができますL`
。"{}"
と書くことができます{}s
。後者は、すべてのブラケットタイプで別のバイトを保存する場合に拡張できます。
"[{<()>}]"
と書くことができます{<()>}a`
。"()<>[]{}"
と書くことができます{<()>}a`$
。特に、ベース変換のトリックは、時々ポップアップする不明瞭なケースに留意するのに役立ちます。例えば[3 2]
あろうE4b
(ベース4における14)。
さらにまれなケースでは、因数分解演算子がmf
役立つことさえあります。例えば[2 7]
ですEmf
。
他の例に出くわした場合は、このリストを自由に拡張してください。
スタック全体をクリアする場合は、配列にラップしてポップします。
];
もう少し注意が必要なのは、多くの計算を行ったが、一番上のスタック要素を保持し、その下のすべてを破棄したい場合です。素朴なアプローチは、変数に一番上の要素を保存し、スタックをクリアし、変数をプッシュすることです。しかし、はるかに短い選択肢があります:スタックを配列にラップし、最後の要素を抽出します:
]W=
(先日これを見せてくれたOptimizerに感謝します。)
もちろん、スタックに要素が2つしかない場合\;
は、より短くなります。
\;
TOSの下の要素のみをポップします。もしかして;;
?
e
そして10のべき乗他の多くの言語と同様1e3
に1000
、CJamの代わりに書くことができます。
これは、整数以外の基数、および整数以外の指数に対しても機能します。例えば、1.23e2
プッシュ123.0及び1e.5
プッシュ3.1622776601683795を(の平方根10)。
すぐには明らかにならないのは、1e3
実際には2つのトークンであるということです。
1
スタックに整数1をプッシュします。
e3
1000で乗算します。
なぜそれが重要なのですか?
e<numeric literal>
既にスタック上にあるものを呼び出すことができます。
2 3 + e3 e# Pushes 5000.
e<numeric literal>
配列にマップできます。
5 , :e3 e# Pushes [0 1000 2000 3000 4000].
ベクトルのユークリッドノルム、つまりその要素の平方和の平方根を計算する簡単な方法は、
2f#:+mq
ただし、はるかに短い方法があります。
mh
、斜辺演算子は、スタックから2つの整数aとbをポップし、sqrt(a 2 + b 2)をプッシュします。
スタック上にベクトルx:= [x 1 …x n ]、n> 1がある場合、:mh
(斜辺によって減少)は以下を達成します。
最初にx 1とx 2がプッシュmh
されて実行され、スタックにsqrt(x 1 2 + x 2 2)が残ります。
次に、x 3がプッシュmh
されて再び実行され、スタックに
sqrt(sqrt(x 1 2 + x 2 2)2 + x 3 2)= sqrt(x 1 2 + x 2 2 + x 3 2)が残ります。
後のx nは処理されている、我々はと残されているのsqrt(X 1 2 +···X N 2)、のユークリッドノルムXを。
場合N = 1及びX 1 <0は、上記のコードは、誤った結果を生成します。:mhz
無条件に動作します。(指摘してくれた@MartinBüttnerに感謝します。)
この答えでこのトリックを初めて使用しました。
CJamは、リストを次の式で数値に変換します:A 0 * n l + A 1 * n l-1 + A 2 * n l-2 + A l * n 0(非負n
)。n
はベースでl
、リストの長さです。これは、A iが任意の整数であり、の範囲にある必要がないことを意味します[0,n)
。
いくつかの例:
0b
最後のアイテムを抽出し、整数にキャストします。W=i
整数ではない場合、バイトのように機能し、保存します。ただし、リスト内の他のすべても整数にキャストできる必要があります。1b
合計を返します。:i:+
整数でなかった場合のように動作し、2バイトを節約します。空のリストでも機能しますが、:+
機能しません。[i{_1&9 32?_@\m2/}16*;]W%:c
文字を行末とタブの文字列に変換します。これは、で変換し直すことができます2bc
。ただし、エンコード関数は、コードゴルフプログラムで簡単に操作することはできません。ただし、通常は必要ありません。次のコードを使用して、文字列を16ビットではないUnicode文字に変換できます2A#b128b:c
。これはで変換できます。(説明は後で追加されます。または、新しいバージョンを後で書くかもしれません。)
128b2A#b " Convert to base 1024. ";
W%2/)W%\:+ " Convert to two base 1024 digit groups. ";
[0X@
{
_54+
@I+_Am>@\-
_Am<@+ 0@-@1^
}fI
]);)
@\+[~+]2A#b_2G#<!{2A#b}*
\W%+:c
同様の方法は、最上位桁を取り除く何らかの方法を見つけることができる場合、n
異なる値modを持つ整数のセットで機能しますn
。
$
三項としての使用ifメモリのリークを気にしない場合、つまり、後でクリアするスタックに未使用の要素を残す];
場合、コピー演算子$
は三項演算子の代わりに便利?
です。
?
選択する2つのアイテムをプッシュする前に条件を計算できればうまく機能しますが、多くの場合、条件は実際にはそれらのアイテムに依存し、それらの上に置くことでより自然になります。
あなたが持っている場合はA B C
、スタック上で、あなたが実行することができます
!$
の代わりに
\@?
真実B
かどうかをコピーC
しA
ます。
場合C
(実際のブール型である0
か1
)、あなたが実行することができます
$
の代わりに
@@?
真実A
かどうかをコピーC
しB
ます。
マトリックスのようなネストされたリストがあるとします:
[[0 1 2][3 4 5][6 7 8]]
または文字列の配列:
["foo""bar"]
そして、ネストされたレベルにブロックをマップする(つまり、各番号または各文字に適用する)必要があります。素朴な解決策は、ネストされてい%
ます:
{{...}%}%
ただし、実際には内部ブロックをスタックにプッシュしてからを使用できますf%
。f
は「追加パラメータ付きのマップ」であるため%
、ブロックを2番目のパラメータとして使用して、外部リストにマップします。
{...}f%
2バイト節約します。
のような何かをするためのもう一つのきちんとしたトリックfor (i=0; i<5; ++i) for (j=0; j<5; ++j) {...}
は
5,_f{f{...}}
外側f
は最初の範囲にマッピングされ、2番目の範囲を追加パラメーターとして提供します。しかし、今度は、f
もう一度使用すると、一番上のスタック要素のみが配列になるためf
、内側のブロックをその上にマッピングし、追加のパラメーターとして外側の「反復変数」を指定します。これは、内部ブロックがスタック上i
およびj
スタック上で実行されることを意味します。
これは、ブロックをデカルト積にマッピングするだけの文字数と同じです(ただし、ペアを配列として必要とする場合、後者は短くなります)。
5,_m*{~...}%
違いは、このバージョンではすべてのペアに対して単一の配列の結果がf
得られるのに対して、double- はネストされたリストを生成することです。これは、結果をグリッドに格納する場合に役立ちます
このトリックを見せてくれたデニスに感謝します。
f
そして:
、自分自身を含む他のオペレーターを採用することで、大幅に改善されました。これは、さらに多くのバイトを節約できることを意味します。ネストされたリストへの演算子のマッピングがさらに短くなりました。
{:x}%
{x}f%
::x
ただし、これはブロックをネストされたリストにマッピングするのにはあまり役立ちません。
デカルト積へのブロックまたは演算子の適用に関しては、ブロックと演算子の場合、これも短くなりました。
5,_f{f{...}}
5,_ff{...}
5,_f{fx}
5,_ffx
素晴らしいのは、これらをネストできるようになったことです。そのため、リストの3番目のレベルに同じように簡単に演算子を適用できます。
:::x
または、いくつかのトリックのあるブロック:
{...}ff%
f~
ん
多くのASCIIアートの課題では、後で重ね合わせるために2つの異なるパターンを生成すると便利です。ベクトル化された演算子は、さまざまな種類の重ね合わせを実現するのに非常に役立ちます。
演算子ベクトル化の有用な特性の1つは、短い文字列/配列の各要素に対して演算子が1回だけ実行され、対応するものがない大きな要素の要素は変更されないことです。
.e<
最小演算子e<
は、文字列、文字、配列、整数のペアに対して機能します。スタックから2つのアイテムをポップし、eを押し下げます。
スペースは、他のすべての印刷可能なASCII文字よりもコードポイントが低いため、.e<
生成されたパターンの一部を「消去」するために使用できます。
"\/\/\/\/\/" " " .e<
e# This pushes " \/\/\/".
完全な例については、Me Want Honeycombへの私の回答を参照してください。
.e>
最大演算子e>
は最小演算子として機能し、逆の結果になります。
繰り返しになりますが、スペースのコードポイントが低いため、スペース.e>
のブロックに印刷可能な文字のパターンを挿入するために使用できます。
[[" " " " " " " "] [" " " " " " " "]][["+" "" "-" ""]["" "*" "" "/"]] ..e>
e# This pushes [["+" " " "-" " "] [" " "*" " " "/"]].
完全な例については、Seven Slash Displayに対する私の回答を参照してください。
.e&
論理AND演算子e&
は、偽の場合は左の引数をプッシュし、そうでない場合は右の引数をプッシュします。
どちらのパターンにも偽の要素が含まれていない場合、これを使用して、あるパターンを別のパターンに無条件に課すことができます。
"################" " * * * *" .e&
e# This pushes " * * * *########".
完全な例については、アメリカ国旗の印刷に対する私の答えをご覧ください!。
.e|
論理OR演算子e|
は、上記のように、引数の順序を逆にして使用できます。
" * * * *" "################" .e|
e# This pushes " * * * *########".
z
および非長方形配列zip演算子z
は、2次元の1配列Aの行と列を転置します。その配列の要素も反復可能です。
非長方形配列の場合- zip
例えば、Python(行を同じ長さに切り捨てる)やRuby(行をでnil
埋める)などの組み込み関数とは異なり、CJamは単純に配列の列を行に変換し、その長さとギャップ。
たとえば、配列を圧縮する
[
[1]
[2 4]
[3 5 6]
]
配列の圧縮と同等です
[
[1 4 6]
[2 5]
[3]
]
または配列
[
[1]
[2 4 6]
[3 5]
]
3つのアクションすべてがプッシュするように
[
[1 2 3]
[4 5]
[6]
]
スタック上。
これは、それz
がインボリューションではないことを意味しますが(これは場合に役立ちます)、いくつかの用途があります。
例えば:
2回圧縮することにより、配列の列を一番上に揃えることができます(つまり、最初の配列を2番目に配列します)。
zz
上記の方法のマイナーな修正は、同様の問題に使用できます。
たとえば、配列の列を下に揃える(つまり、2番目の配列を最初の配列にする)には、行の順序を逆にして2回圧縮できます。
W%zzW%
文字列の配列を指定すると、次のように最長の文字列の長さを計算できます。
:,:e>
ただし、結果の行数を圧縮して計算することで、3バイトを節約できます。
z,
1 Aの「行」のいずれかが反復可能でない場合、それらをシングルトンとして扱うため、zipは任意の配列に対して機能します。z
z
ですが、空の値がスキップされている間に列を行に変換することを想像すると、私にとっての動作ははるかに論理的です。この例では、入力の最初の列は1、2、3、2番目の列は4、5(空の位置はスキップされます)、3番目の列は6です。これらは結果の行です。
CJamでは例外はすべて致命的です。以来STDERRへの出力は、デフォルトでは無視され、我々は我々の利点にこれを使用することができます。
CJamのすべての演算子は、スタックから0個以上の要素をポップし、何らかのタスクを実行し、スタック上で0個以上の要素をプッシュすることで機能します。タスクの実行中に例外が発生するため、要素は引き続きポップされますが、代わりにプッシュされるものはありません。
以下にいくつかの使用例を示します。
小さなスタックをクリアする
2つの要素を含むスタックをクリアするに@
は、使用できます。@
3つのスタック要素をポップしようとしますが、2番目のスタック要素をポップした後に失敗します。
3つの要素をポップする他の演算子も同じ目的に役立ちます。
アクションでそれを参照してくださいここに。
スタックから2つまたは3つの要素を削除する
これらの特定の要素に実装されていない演算子は、終了する直前にスタックから2つまたは3つの要素をポップするために使用できます。
2つの要素をポップするためにb
、それらの1つが文字であるか、いずれも整数でない場合に機能します。
3つの要素をポップするにt
は、一番下の2つが反復可能でない場合、一番下の反復可能が空である場合、またはそれらのいずれも整数でない場合に機能します。
ループを抜ける
場合によっては、整数がゼロになるか、文字列が短くなりすぎるとループを終了する必要があります。これらの条件をテストするのではなく、関係する操作がゼロ、空の文字列、またはシングルトンで失敗した場合、プログラムに自然なコースをとらせることができます。
条件付き実行
特定のタイプの入力に対してソースコードを実行しない場合、その種の入力に失敗する演算子を使用できる場合があります。
たとえばi
、整数に評価されないew
文字列では失敗し、長さ0または1の文字列では失敗します。
アクションでそれを参照してくださいここに。
初心者向けです!
配列から最大数または最小数を見つける必要がある場合、最も簡単で最小の方法は、配列をソートしてから最初または最後の要素を取り出すことです。
配列が変数内にある場合 A
A$W=
最大
A$0=
最小値です。
両方を同時に取得することも可能です
A$)\0=
これは読んだ後は明らかなように見えるかもしれませんが、誰もが最初の試みは、配列の使用e<
またはe>
配列の反復を経由する傾向があります。
A{e<}*
これは2バイト長くなり、最大と最小の両方が必要な場合はさらに長くなります。
(
andの)
代わりに0=
andを使用できますW=
。
:e<
と:e>
非常に大きいが、任意の数が必要な場合は、通常、次のような科学表記法を使用するか9e9
、大きな組み込み変数のいずれかを同様の累乗、たとえばのように累乗しKK#
ます。ただし、実際の数値が何であるかを気にせず、一貫して同じである必要がない場合(たとえば、乱数の上限として)、次を使用して2バイトで実行できます。
es
代わりに。これは、ミリ秒単位の現在のタイムスタンプを提供し、10 12のオーダーです。
e9
。
2つの文字列または配列が等しくない場合に真実の値が必要な場合があり、そうであれば偽の値が必要です。明らかな解決策は2バイトです。
=!
等しいかどうかを確認し、結果を逆にします。ただし、いくつかの条件下では、使用できます
#
場合には、#
第一(及びあなたのサブアレイが開始インデックスを与える)のサブアレイとして二番目の配列のための2つのアレイが実際の検索に適用されます。そのため、2つの配列が同じである場合、0
サブ配列は開始時にすぐに検出され、偽になります。しかし、2番目の配列が見つからない場合は、-1
どちらが真実かを示します。
2つの配列に追加条件が必要な理由は、2番目の配列が最初の配列の自明ではない接頭辞である場合、偽の値も生成されるためです。
"abc""ab"#
0
文字列は同じではありませんが与えます。この場合を除外する最も単純な条件は、両方の配列が同じ長さになることを知っている場合です。その場合、一方が他方のプレフィックスである場合、それらが等しいことがわかります。しかし、特定の状況では、より弱い条件でも十分な場合があります。たとえば、文字列がソートされていることがわかっている場合、プレフィックスは常に2番目ではなく最初の文字列になります。
配列があり、その配列のすべての可能なサブセットを持つ配列が必要だとします。トリックは、空の配列から始めてから、各要素について、既に持っているサブセットを複製し、それらに新しい要素を追加することです(要素が追加されなかった以前の結果を保持します)。基本ケース、つまり空の配列のみを含む配列でスタックを初期化する必要があることに注意してください。これは次のようになります。
[1 2 3 4 5]La\{1$f++}/
これの良い点は、サブセットで計算をすぐに実行できることです。文字を追加する必要はありません。すべてのサブセットの製品が必要だとします。その場合、基本ケースはを含む配列1
であり、各ステップで、可能な製品の前のリストを取得して複製し、複製内のすべてに新しい要素を乗算します。
[1 2 3 4 5]1a\{1$f*+}/
0=
文字列用配列の最初の要素を取得するには、使用する必要があります0=
(または(
、残りの配列をスタックに残しても構わない場合は、)。
ただし、その配列が文字列の場合、文字にキャストするだけで十分です。
"xyz"c e# Pushes 'x.
c
配列の最初の要素を抽出させないのかわかりません。これはより便利で一貫性があります。
CJamには左回転演算子m<
があります。これは通常、任意の数のユニットを左に配列を回転させるために使用するものです。
では、いくつかのケースでは、あなたも使用することができます(+
シフトおよび追加します:
[1 2 3] (+ e# Pushes [2 3 1].
[[1] [2] [3]] (+ e# Pushes [[2] [3] 1].
配列の最初の要素も反復可能であるため、2番目の例は機能しませんでした+
。したがって、追加ではなく連結されました。
また、スタック上の回転した配列をダンプする場合は、:\
無条件で使用できます(スワッピングによって削減)。
[1 2 3] :\ e# Pushes 2 3 1.
[[1] [2] [3]] :\ e# Pushes [2] [3] [1].
openがない限り[
、このトリックを使用してスタック全体を回転させることもできます。つまり、一番下のスタックアイテムを一番上に移動します。
]:\
スタックに文字列/数字/などのリストがあるとしましょう。上部に、その下に他の追加アイテムがあります。すなわち
123 "waste" ["a" "b" "rty" "print" "me" "please"]
今、あなたは最後のリストのみを印刷することに興味があるので、
S*]W=
どの出力
a b rty print me please
スタッククリアトリックを使用して、スペースで結合されたリストのみを印刷するため、これは本当に賢いようです(リストを印刷するための望ましい方法ではない場合があります)。
これはさらにゴルフすることができます!
p];
それは2バイト短くなります!
リスト以外のスタックにアイテムが1つしかない場合は、さらに短くなります!
p;
美しさはp
、それがスタックから最上位の項目を削除することであるstringifiesそれは(また終了時に改行を追加)し、コードの完了を待たずに、即座にSTDOUTに印刷します。
したがって、上記のコードは出力されます
["a" "b" "rty" "print" "me" "please"]
これは、リストがスタックにあったときの正確な表現です!
CJamには、m*
スタック上の上位2つの配列リスト/文字列を取得し、そこから可能なすべてのペアを作成する、デカルト積計算機が組み込まれています。例えば
[1 2 3 4]"abc"m*
葉
[[1 'a] [1 'b] [1 'c] [2 'a] [2 'b] [2 'c] [3 'a] [3 'b] [3 'c] [4 'a] [4 'b] [4 'c]]
スタックとして
しかし、3つ以上のリスト/文字列から可能なすべての組み合わせが必要な場合はどうでしょう。あなたはm*
何度も使用しますか?例えば
[1 2 3 4][5 6]"abc"m*m*
スタックに次のものを残します
[[1 [5 'a]] [1 [5 'b]] [1 [5 'c]] [1 [6 'a]] [1 [6 'b]] [1 [6 'c]] [2 [5 'a]] [2 [5 'b]] [2 [5 'c]] [2 [6 'a]] [2 [6 'b]] [2 [6 'c]] [3 [5 'a]] [3 [5 'b]] [3 [5 'c]] [3 [6 'a]] [3 [6 'b]] [3 [6 'c]] [4 [5 'a]] [4 [5 'b]] [4 [5 'c]] [4 [6 'a]] [4 [6 'b]] [4 [6 'c]]]
製品はまだペアであり、アイテムの1つがペアそのものであることに注意してください。これは予期されていないため、フラット化された組み合わせが必要です。
それを行う簡単な方法があります。デカルト積に必要なすべてのリストを配列にラップし、デカルト積をペアワイズで作成し、毎回フラット化します。
[1 2 3 4][5 6]"abc"]{m*{(+}%}*
これは去る
[['a 5 1] ['b 5 1] ['c 5 1] ['a 6 1] ['b 6 1] ['c 6 1] ['a 5 2] ['b 5 2] ['c 5 2] ['a 6 2] ['b 6 2] ['c 6 2] ['a 5 3] ['b 5 3] ['c 5 3] ['a 6 3] ['b 6 3] ['c 6 3] ['a 5 4] ['b 5 4] ['c 5 4] ['a 6 4] ['b 6 4] ['c 6 4]]
スタック上。
注文を維持したいですか?、ポップしたアイテムを配列に追加する前に、単にスワップします。すなわち
{m*{(\+}%}*
順列のみが必要ですか?
{m*{(+$}%_&}*
組み合わせで一意の要素のみが必要ですか?
{m*{(+_&}%}*
それはすべての人々です。今のところ。
]:m*:e_
で、任意の数のアレイを使用して行うこともできます
複雑なデータ構造で作業している場合、その中のアイテムは単純ですが、文字列に変換すると役立つ場合があります。
たとえば、ビットの2D配列の最初または最後のいくつかのアイテムを取得し、返されるタイプを気にしない場合は、またはsA<
からバイトを保存します。0=A<
:+A<
または、入力の一部のビットを変更する場合は、評価する前に文字列を変更できます。
または、この構造を取得して、単純なリストに変換する場合:
[[[[[[[[[1]2]3]4]5]6]7]8]9]
他の方法で多くのキャラクターでそれを行うことができます:
[a{~)\}h;]W%
ただし、文字列を使用するとはるかに短くなります。
s:~
1桁以上の数字がある場合でも、より短くなります。
[`La`-~]
または:
`']-~]
そのような配列の多くを含む別の配列が必要ない場合。
e_
今があります
s
まだうまく機能します。
N
代わりに、La
多くの場合、空の配列を唯一の要素として含む配列に初期化されたものが必要ですLa
。
多くの場合、印刷前に各要素の後に改行を追加する必要があります。これは、No
またはのようなものN*
です。
しかし、両方が当てはまる場合N
、改行文字を唯一の要素として持つ配列を使用して配列を初期化できることがわかります。コードの残りの要素にのみ先頭に追加するようにしてください。先頭に追加するのは常に文字または配列です。または、先頭の改行が許容され、それが短くなる場合にのみ追加します。
S
出力をスペースで区切る必要がある場合にも機能する場合があります。
まれに、初期要素は文字列でなければなりません。ただしNa
、後で改行を追加するよりも短い方を使用できます。
文字列が"abbcdbbfghbdbb"
あり、それを分割したいとしますb
"abbcdbbfghbdbb"'b/
これはスタックに残ります:
["a" "" "cd" "" "fgh" "d" "" ""]
空の文字列に注意してください?それらが存在するのは、2つb
が一緒になっていて、その間に何もなかったからです。時々、あなたはこれを避けたいです。あなたはこれをすることができます
"abbcdbbfghbdbb"'b/La-
または空の文字列を除外する
"abbcdbbfghbdbb"'b/{},
しかし、それは3バイト余分です。
この特定のユースケースのあまり知られていない演算子は%
です。modとmapを実行し、数値("abcd"2%
= "ac"
)に基づいて分割する以外に、%
文字列/配列で分割することもできます。したがって、上記のユースケースの場合:
"abbcdbbfghbdbb"'b%
残します
["a" "cd" "fgh" "d"]
スタック上。
今日の私の回答の1つでこれを指摘してくれた@ user23013に感謝します。
我々は持っている:x
の省略形として{x}%
およびまたは{x}*
(かどうかに応じてx
単項またはバイナリです)。残念ながら、短縮する同等の挿入演算子はありません{x}/
。しかし、非常に頻繁に行うのは{x}/
、x
実際にはスタックの下にあるアイテムを繰り返し変更する二項演算子です。その場合で、アイテムが配列ではない場合、fold / reduceをforeachとして乱用することでバイトを節約できます。
5 [1 2 3 4]{-}/ e# Gives -5
5 [1 2 3 4]+:-
これは、foldが常に最初の要素に手を加えないために機能します。残念ながら、変更された要素が配列の場合、追加するとラップが解除されるため、バイトは保存されません。ただし、幸運にも配列の先頭にその要素が含まれている場合があります。その場合、reduceを念頭に置く必要があります({}/
残りの要素を使用する前に要素を手動で削除する代わりに)。
CJamにはprint
演算子:がありo
ます。動作しますが、すべてのコードが実行された直後にスタックが印刷されます。プログラムの最後でスタックをクリアすると、停止できます。最後にこれを置くだけです:
];
printlnには、oNo
またはp
(として機能する`oNo
)を使用できます
o
ありp
ます。p
まず、印刷するアイテムを明確な文字列表現に変換します。p
は、実行と同等`oNo
です。