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