0
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

[Julia] ... (splat, slurp)

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
0
Help us understand the problem. What are the problem?