Edited at

[Julia] ... (splat, slurp)

More than 1 year has passed since last update.

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 (音を立てて飲食する) と呼ばれます。

参考

* https://hydrocul.github.io/wiki/programming_languages_diff/function/var-args.html


実引数のリストを、複数に展開する (splat)

参照:

* http://docs.julialang.org/en/stable/manual/faq/#combines-many-arguments-into-one-argument-in-function-definitions

関数呼び出しで、実引数のリストやタプルを、複数の実引数に展開してから、呼び出します。

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