Julia ミニパターン。Julia 独特の構文を、不定期に紹介したいと思います。
初回は ...
について。
可変長の仮引数 (slurp)
参照:
- http://docs.julialang.org/en/stable/manual/functions/#varargs-functions
- http://docs.julialang.org/en/stable/manual/faq/#combines-many-arguments-into-one-argument-in-function-definitions
関数定義で、仮引数の名前に ...
を続けると、任意の数の実引数を受け取れます。仮引数は tuple になります。
julia> function foo(v...)
@show v
end
foo (generic function with 1 method)
julia> methods(foo)
# 1 method for generic function "foo":
foo(v...) at REPL[1]:2
julia> foo(1)
v = (1,)
(1,)
julia> foo(1,"a")
v = (1,"a")
(1,"a")
julia> foo(1,"a", [3,4])
v = (1,"a",[3,4])
(1,"a",[3,4])
Python, Ruby では、可変長仮引数の前に *
をつけますね。この構文は slurp (音を立てて飲食する) と呼ばれます。
参考
実引数のリストを、複数に展開する (splat)
参照:
関数呼び出しで、実引数のリストやタプルを、複数の実引数に展開してから、呼び出します。
julia> function bar(x,y,z)
@show x
@show y
@show z
end
bar (generic function with 1 method)
julia> bar(1,2,3)
x = 1
y = 2
z = 3
julia> bar([1,2,3]...)
x = 1
y = 2
z = 3
julia> bar((1,2,3)...)
x = 1
y = 2
z = 3
bar([1,2,3]...)
と bar((1,2,3)...)
は、bar(1,2,3)
と同じです。
こちらの機能は splat と呼ばれています。splat 「ピシャ」(濡れた物を床にたたきつけるときの擬音語)
例: 任意の数のベクトルから、行列を作る。
私が書いた例を紹介します。
ベクトルを値とする辞書を作っておきます。(Dictでは、キーの並び順は決まっていません)
julia> vdict = Dict(
"a" => [1,1,0],
"b" => [1,0,1],
"c" => [0,1,1],
"d" => [2,1,1] )
Dict{String,Any} with 4 entries:
"c" => [0,1,1]
"b" => [1,0,1]
"a" => [1,1,0]
"d" => [2,1,1]
キーを用いて、ベクトルをいくつか選びます。Comprehension [ ___ ]
で、ベクトルのリストを作ります。
julia> [ vdict[k] for k in ["d","a", "c"] ]
3-element Array{Array{Int64,1},1}:
[2,1,1]
[1,1,0]
[0,1,1]
これらの列ベクトルを並べて、行列を作りましょう。hcat
を用いたいのですが、リストを引数にとれません。そこで、上のリストを ...
で展開します。
julia> hcat( [ vdict[k] for k in ["d","a", "c"] ]... )
3×3 Array{Int64,2}:
2 1 0
1 1 1
1 0 1
ワンラインで大満足です。ベクトルの数によらず、同じ構文で OK です。
※ この件に限れば reshape
で可能ですが、要素を数えないといけません。Fortran や C なら、行列を用意して、要素毎にコピーするのでしょうが、もう面倒です。
[追記 2017/01/30]
本記事直下のコメントの通り、comprehension (リスト内包表記) [ ___ ]
より、generator ( ___ )
を使う方が、上の例の性能が改善します。 Julia 0.5 の generator の紹介は、コメント主 @antimon2 さんの記事をご覧ください。→ http://qiita.com/antimon2/items/89562cf7c1115c500f02