ジュリアでゴルフをするための一般的なヒントは何ですか?私は、ゴルフの一般的な問題をコード化するのに適用できる、少なくともジュリア特有のアイデアを探しています(たとえば、「コメントの削除」は答えではありません)。
ジュリアでゴルフをするための一般的なヒントは何ですか?私は、ゴルフの一般的な問題をコード化するのに適用できる、少なくともジュリア特有のアイデアを探しています(たとえば、「コメントの削除」は答えではありません)。
回答:
注:ジュリアの構造はまだ安定していないため、以下に古いヒントが含まれている場合があります。
いくつかのキャラクターを保存するためのいくつかのトリック
\ =div
、のa\b
代わりに入力できますdiv(a,b)
。スペースに注意してください-これは、「\ =」演算子として解析されないようにするために必要です。また、REPLプロンプトレベルで過負荷になった場合は、(\)=Base.(\)
または\ =Base. \
を使用してリセットしてください。注:一部の関数には、Alex Aが指摘しているように、÷
for などの既存のUTF-8演算子が事前に定義div
されています。a>0?"Hi":""
、使用"Hi"^(a>0)
1つのバイトを保存する、またはブール値A、使用のための"Hi"^a
3つのバイトを保存します。a=split("Hi there"," ")
、あなたが避けることができるかもしれませa[1]
およびa[2]
使用しa,b=split("Hi there"," ")
て参照することができ、a
およびb
割り当てのちょうど2つの余分な文字のコストで、それぞれの使用のための3バイトを保存し、。明らかに、ベクトル演算を使用できる場合は、これを行わないでください。[]
-配列の場合、式A[]
はと同等A[1]
です。これは、最初の文字を取得したい場合は文字列、またはタプルでは機能しないことに注意してください。==[]
列にisemptyを使用しないでください -代わりに、配列および==()
タプルに使用してください。同様に、ネガティブの場合、とを使用!=[]
し!=()
ます。文字列の場合==""
、空の場合に使用しますが、空で>""
はない場合に使用します。これは、 ""が辞書的に他の文字列の前にあるためです。x<=1&&"Hi"
として記述できx>1||"Hi"
、文字を保存します(ブール値の戻り値が重要でない限り)。in('^',s)
ではなくcontains(s,"^")
。他の文字を使用できる場合、でもう少し節約できますが、UTF-8では3バイトである'^'∈s
ことに注意してください∈
。minimum(x)
あるいはmaximum(x)
、使用min(x...)
またはmax(x...)
あなたが知っていれば、あなたのコードをオフ1つの文字を剃るために、x
少なくとも2つの要素を持つことになります。または、のすべての要素がx
負でないことがわかっている場合は、minabs(x)
またはmaxabs(x)
r"(?m)match^ this"
、type r"match^ this"m
、3文字を保存しないでください。reverse(x)
よりも1バイト長くflipud(x)
、後者の方が優れています。{[1,2]}
ではありません{1,2}
)-Julia 0.4の場合はが必要Any[[1,2]]
です。end
配列のインデックス付け内で使用すると、自動的に配列/文字列の長さに変換されます。ではなくk=length(A)
、を使用A[k=end]
して3文字を保存します。kをすぐに使用する場合、これは有益ではないことに注意してください。これは多次元の場合にも機能します- A[k=end,l=end]
各次元のサイズを取得しますA
-ただし、(k,l)=size(A)
この場合は1バイト短くなりますので、同時に最後の要素にすぐにアクセスしたい場合にのみ使用してください。A[k=1:end]
この場合k
、イテレータマッチングを保持します1:length(A)
。これはA
、同時に配列も使用する場合に便利です。collect(A)
、[A...]
同じことを行い、4バイトを節約します。"$(s[i])"
またはdec(s[i])
を使用し"$i"
ます。?:
代わりに、&&
または||
条件付き割り当てに使用します。つまり、特定の条件でのみ割り当てを実行する場合、、またはではなくを書き込むことcond?A=B:1
で1バイトを節約できます。ここで、はダミー値であることに注意してください。cond&&(A=B)
cond?1:A=B
cond||(A=B)
1
union
またはの∪
代わりにunique
- union(s)
を使用すると、と同じことが行わunique(s)
れ、プロセスに1バイトが保存されます。ASCII以外の文字を使用できる場合∪(s)
、同じことを行い、∪
コストはの5バイトではなく3バイトになりますunion
。split("Hi there")
pattern引数はデフォルトでスペースになっているため、単にスペースを使用して分割できます。
演算子を再定義すると、括弧とコンマで大量のバイトを節約できます。
単項の例については、フィボナッチ数列の次の再帰的な実装を比較してください。
F(n)=n>1?F(n-1)+F(n-2):n # 24 bytes
!n=n>1?!~-n+!(n-2):n # 20 bytes
!n=n>1?!~-n+!~-~-n:n # 20 bytes
再定義された演算子は、最初の優先順位を保持します。
私たちは単純に入れ替えることができなかったことをノート!
に賛成して~
いるので、~
すでに整数のために定義されている間、!
唯一のブール値のために定義されています。
再帰がなくても、演算子の再定義は二項関数の定義よりも短くなります。単純な可分性テストの次の定義を比較してください。
f(x,y)=x==0?y==0:y%x==0 # 23 bytes
(x,y)->x==0?y==0:y%x==0 # 23 bytes
x->y->x==0?y==0:y%x==0 # 22 bytes
x\y=x==0?y==0:y%x==0 # 20 bytes
以下は、二項演算子を再定義してアッカーマン関数を計算する方法を示しています。
A(m,n)=m>0?A(m-1,n<1||A(m,n-1)):n+1 # 35 bytes
^ =(m,n)->m>0?(m-1)^(n<1||m^~-n):n+1 # 36 bytes
| =(m,n)->m>0?m-1|(n<1||m|~-n):n+1 # 34 bytes
m\n=m>0?~-m\(n<1||m\~-n):n+1 # 28 bytes
^
優先度が高すぎるため、通常の識別子を使用するよりも長いことに注意してください。
前に述べたように
m|n=m>0?m-1|(n<1||m|~-n):n+1 # 28 bytes
|
この場合は既に定義されているため、整数引数に対しては機能しません。整数の定義は次のように変更できます
m::Int|n::Int=m>0?m-1|(n<1||m|~-n):n+1 # 38 bytes
しかし、それは法外に長いです。ただし、floatを左の引数として、整数を右の引数として渡すと機能します。
factor(n)に簡単に惑わされないでください。魅力的なベースライブラリ関数factor(n)
には致命的な欠陥があります。整数の因数分解を順序付けられていないDict
型で返します。したがって、それはコストのかかる必要ですcollect(keys())
とcollect(values())
、潜在的にも、cat
そしてsort
あなたはそれのうち望んでいたデータを取得します。多くの場合、試験部門ごとにファクタリングする方が安価です。悲しいが本当。
使用マップ map
は、ループの優れた代替手段です。違いに注意してくださいmap
とmap!
し、ときにすることができ、後者のインプレース機能を活用します。
mapreduceを使用する mapreduce
、mapの機能がさらに拡張され、バイトを大幅に節約できます。
匿名関数は素晴らしいです!..特に前述のmap
関数に渡される場合。
累積配列関数 cumprod
、cumsum
、風味cummin
及び他の同様の名前の関数はn次元配列の指定された次元に沿った累積動作を可能にします。(または、配列が1-dの場合は* un *指定)
Anyの短い表記法多次元配列(またはDict)の特定の次元をすべて選択する場合、たとえばA[Any,2]
、次を使用してバイトを節約できます。A[:,2]
関数の代わりに単一行の表記を使用function f(x) begin ... end
するf(x)=(...)
三項演算子を使用する単一式のIf-Then-Else構文の場合は、スペースを節約できます。警告:他の一部の言語では可能ですが、ジュリアではコロンの後の部分を省略できません。また、Juliaの演算子は式レベルであるため、コードブロック全体の条件付き実行には使用できません。
if x<10 then true else false end
対
x<10?true:false
これは他の言語でも可能ですが、通常は簡単な方法よりも長くなります。ただし、ジュリアの単項演算子と二項演算子を再定義する機能により、非常にゴルファーになります。
たとえば、1〜10の自然数の加算、減算、乗算、および除算テーブルを生成するには、次のようにします。
[x|y for x=1:10,y=1:10,| =(+,-,*,÷)]
その再定義バイナリ演算子|
として+
、-
、*
および÷
、その後、計算x|y
操作ごととx
し、y
所望の範囲内。
これは単項演算子でも機能します。たとえば、複素数1 + 2i、3-4i、-5 + 6i、および-7-8i、それらのネガ、それらの複素共役、およびそれらの逆数を計算するには、
[~x for~=(+,-,conj,inv),x=(1+2im,3-4im,-5+6im,-7-8im)]
その再定義単項演算子~
として+
、-
、conj
およびinv
、その後、計算~x
すべての所望の複素数のため。
女性と男性のシーケンス(バイナリ)
ケース順列(単項)
キーワードは、スペースやセミコロンを必要とせずに、定数のすぐ後に続くことがあります。例えば:
n->(for i=1:n n-=1end;n)
1
との間にスペースがないことに注意してくださいend
。これはend
、親括弧の後に起こる場合にも当てはまります)end
。
演算子をオーバーロードするの÷
ではなく、使用して整数除算を実行しdiv()
ます。÷
UTF-8では2バイトの価値があることに注意してください。
可能な場合ではなく、vec()
or A[:]
(一部の配列の場合A
)を使用しreshape()
ます。
チャレンジルールで許可されている場合、完全なプログラムではなく機能を作成します。stdinから読み取って変数を定義するのではなく、入力を受け入れる関数を定義する方が簡単です。例えば:
n->(n^2-1)
n=read(STDIN,Int);n^2-1
変数は、関数の引数内でインクリメントできます。たとえば、次のとおりである私の答えに次の1-スパースバイナリ番号検索挑戦:
n->(while contains(bin(n+=1),"11")end;n)
これはn
、ループ内でインクリメントするよりも短いです。