LoginSignup
4
1

More than 5 years have passed since last update.

[Julia] ... (splat, slurp)

Last updated at Posted at 2017-01-29

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

4
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1