Julia特有の構文メモ
Symbol
Symbol("test") #のように使う
文字列を表すが、Symbolは常に同じオブジェクトであることが保証されるため、メモリ効率がいい. DataFrameのラベル名などに使われる.
ショートカット構文
条件 || 実行文 #左辺が偽のときだけ実行される 条件 && 実行文 #左辺が真のときだけ実行される
コメントアウト
#=
と=#
で囲うと複数行のコメントアウト.
レンジ
for i in 1:10 #1と10は生成される列に含まれる println("$i") end collect(10:-2:1) #ステップサイズは3組にして真ん中で指定 10 8 6 4 2
文字と文字列
julia> 'a' #chracter 'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase) julia> "a" #string "a" julia> 'ab' #文字列(string)になっているのでエラーになる ERROR: syntax: invalid character literal Stacktrace: [1] top-level scope at REPL[26]:0 julia> "ab" #こちらは大丈夫 "ab" julia> abcdef = "abcdef" "abcdef" julia> abcdef[2] #インデックス指定もできる(1オリジン) 'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase) julia> abcdef[3:end] "cdef" julia> abcdef[3:end-1] "cde" julia> abcdef[:4] 'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase) julia> ghijk = "ghijk" "ghijk" julia> abcdef * ghijk #文字列の結合 "abcdefghijk" julia> string(abcdef,ghijk) #これでもOK "abcdefghijk" julia> println(abcdef) abcdef julia> println("$abcdef") #文字列内での展開 abcdef julia> println("$abcdef","$ghijk") abcdefghijk julia> println("1+2=$(1+2)") #カッコでくくると計算も展開できる 1+2=3 julia> raw"1+2=$(1+2)" #rawをつけるとraw文字列になる "1+2=\$(1+2)"
if文
julia> x=3; y=5; julia> if x < y println("$x is smaller than $y") end 3 is smaller than 5 julia> if x < y < 4 #3つ以上の項目を書ける println("$x < $y < 4 です") else println("$x < $y < 4 ではありません") end 3 < 5 < 4 ではありません julia> if x < y < 4 res_str = "$x < $y < 4 です" end #ifブロック内のみの変数は、ifブロック内で使われなかった場合はエラーになる julia> println(res_str) ERROR: UndefVarError: res_str not defined Stacktrace: [1] top-level scope at REPL[5]:1 julia> if x < y < 4 res_str = "$x < $y < 4 です" else res_str = "$x < $y < 4 ではありません" end "3 < 5 < 4 ではありません" #elseの中で使われているのでエラーにならない julia> println(res_str) 3 < 5 < 4 ではありません julia> x = 1; ifelse(x > 1, x + 1, x + 2) #trueだったら左、falseだったら右を返す 3
3項演算子
r = 5 > 3 ? 5 : 3 #?の左の式が真だったら:の左を出力、偽だったら右を出力 5 #こんなこともできる julia> println(5 > 3 ? "5は3より大きい" : "5は3より大きくない") 5は3より大きい #if-elseif-elseみたいにできる julia> println(5 > 3 ? 5==3 ? "5は3に等しい" : "5は3より大きい" : "5は3より大きくない") 5は3より大きい #関数の定義にも使える($aの後ろにはスペースが必要、エスケープもできなさそう) julia> is_morethan(a,b) = println(a > b ? "$a は$b より大きい" : "$a は$b より大きくない") is_morethan (generic function with 1 method) julia> is_morethan(10,50) 10 は50 より大きくない
while文
julia> i = 1 1 #v1.0以降ではグローバルスコープの変数を書き換える場合はglobalを入れないとエラーになる julia> while i <= 3 println(i) i += 1 end ERROR: UndefVarError: i not defined Stacktrace: [1] top-level scope at ./REPL[25]:2 #こうするとうまくいく julia> while i <= 3 println(i) global i += 1 end 1 2 3
for文
julia> for j = 1:3 #:でもいい println(j) end 1 2 3 julia> for j in 1:3 #inでもいい println(j) end 1 2 3 julia> for j in [1,2,3] #配列を参照してもいい println(j) end 1 2 3 julia> for j in "123" #文字列を参照してもいい println(j) end 1 2 3 julia> for i = 1:2, j in "abc" #多重ループも1行で書ける println(i,j) end 1a 1b 1c 2a 2b 2c julia> arr = [x for x = 1:3] #内包表記 3-element Array{Int64,1}: 1 2 3 julia> [(i,j) for i = 1:2, j in "abc"] #複数要素をtupleに入れながら、2次元配列を返す 2×3 Array{Tuple{Int64,Char},2}: (1, 'a') (1, 'b') (1, 'c') (2, 'a') (2, 'b') (2, 'c') julia> println([i for i in 1:200 if i % 16 == 0]) #if文を入れることもできる [16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192] julia> [3x + 5y for x = 1:3, y = 5:7] #こんなことも 3×3 Array{Int64,2}: 28 33 38 31 36 41 34 39 44
配列
#Array{T,N}(undef,dims)と書く #Int64型 2次元 1次元の要素数3,2次元の要素数3 #数字は勝手に適当なものが入る julia> arrtwoint1 = Array{Int64,2}(undef,3,3) 3×3 Array{Int64,2}: 4592616224 4592617456 4592618576 4592616224 4592618576 4415784480 4413668112 4592617456 4592618576 julia> arrtwoint1 = [1 2 3; 4 5 6; 7 8 9] 3×3 Array{Int64,2}: 1 2 3 4 5 6 7 8 9 julia> arrtwoint1[2,2] #[2][2]ではない 5 julia> arrtwoint1[2,3] #2行目3列 6 julia> arrtwoint1[1:3] #1:3行目1列 3-element Array{Int64,1}: 1 4 7 julia> arrtwoint1[1:3,2] #1:3行目2列 3-element Array{Int64,1}: 2 5 8 julia> arrtwoint1[2,1:3] #2行目1:3列 3-element Array{Int64,1}: 4 5 6 julia> [[1,2,3],[4,5,6]] #これは2次元ではなく1次元配列なので注意 2-element Array{Array{Int64,1},1}: [1, 2, 3] [4, 5, 6] julia> [1 2 3; 4 5 6] #正しくはこう書く(行列) 2×3 Array{Int64,2}: 1 2 3 4 5 6
文字列を配列にする.
julia> li = split(str, ",")
配列はカンマ区切り
julia> an = [1,2,3] 3-element Array{Int64,1}: 1 2 3 julia> push!(an,4) #要素を追加 4-element Array{Int64,1}: 1 2 3 4 julia> pop!(an) #最後の要素を削除 4 julia> an 3-element Array{Int64,1}: 1 2 3
行列はスペース区切り
julia> an = [1 2 3] 1×3 Array{Int64,2}: 1 2 3 julia> an = [[1,2,3] [4,5,6] [7,8,9]] #要素の値に配列を入れれば2次元の行列になる 3×3 Array{Int64,2}: 1 4 7 2 5 8 3 6 9 julia> an = [1 2 3; 4 5 6; 7 8 9] #こちらも行列. しかし格納の順番(方向)が異なる 3×3 Array{Int64,2}: 1 2 3 4 5 6 7 8 9 #つまりJuliaではPythonのNumPyの機能が標準装備されている julia> ([1,2,3] == [1 2 3], [1,2,3] == [1; 2; 3]) (false, true) julia> (reshape([1,2,3,4,5,6],2,3) == [1 3 5; 2 4 6]) true #行列の回転 julia> mtr = reshape([i for i in 1:16],4,4) 4×4 Array{Int64,2}: 1 5 9 13 2 6 10 14 3 7 11 15 4 8 12 16 julia> rot180(mtr) #180度回す 4×4 Array{Int64,2}: 16 12 8 4 15 11 7 3 14 10 6 2 13 9 5 1 julia> rotl90(mtr) #90度左(left)に回すrotl90関数. 右に回すrotr90もある 4×4 Array{Int64,2}: 13 14 15 16 9 10 11 12 5 6 7 8 1 2 3 4 julia> rotl90(mtr,3) #回転数の指定もできる 4×4 Array{Int64,2}: 4 3 2 1 8 7 6 5 12 11 10 9 16 15 14 13 #応用 julia> reshape([i for i in 1:64 if i % 4 ==0],4,4) 4×4 Array{Int64,2}: 4 20 36 52 8 24 40 56 12 28 44 60 16 32 48 64
辞書(Dict)型
Dict(:a => 1, :b => 2)
辞書型. Dict()関数で作成する. Pairと呼ばれる=>で区切られる構造を引数として与えることで、リテラルっぽく書くことができる.
dict = Dict{Int64,Int64}() dict = Dict{Int64,Dict}() #valueを辞書型にすることもできる(これで2次元ハッシュみたいな).
初期宣言.
julia> Dict("a" => 1, "b" => 2) Dict{String,Int64} with 2 entries: "b" => 2 "a" => 1 julia> dict_test = Dict([("a",1),("b",2)]) #Tuple型の配列を入れてもいい Dict{String,Int64} with 2 entries: "b" => 2 "a" => 1
キーはStr,Int,Floatでもいいが、定義した型から外れる他の型は代入できない.
dict_test["a"] = "20" ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int64 Closest candidates are: convert(::Type{T<:Number}, ::T<:Number) where T<:Number at number.jl:6 convert(::Type{T<:Number}, ::Number) where T<:Number at number.jl:7 convert(::Type{T<:Integer}, ::Ptr) where T<:Integer at pointer.jl:23 ... Stacktrace: [1] setindex!(::Dict{String,Int64}, ::String, ::String) at ./dict.jl:380 [2] top-level scope at REPL[76]:1
julia> dict_test["a"] = 20 20
forループでキーと値を取得 そのまま受けるとPair型のオブジェクト
julia> for item in dict_test println(item) end "b" => 2 "a" => 20
(key, value)形式で受ける
julia> for(name,price) in dict_test println("$name : $price") end b : 2 a : 20
特定の要素の有無を確認
julia> haskey(dict_test,"aa") false julia> haskey(dict_test,"a") true
値を取得する: get(collection,key,default)
julia> get(dict_test,"a",120) #default(120の部分)はオプショナルでなく必須. 20
julia> keys(dict_test) Base.KeySet for a Dict{String,Int64} with 2 entries. Keys: "b" "a"
julia> values(dict_test) Base.ValueIterator for a Dict{String,Int64} with 2 entries. Values: 2 20
要素の削除: delete! (要素削除後の辞書を返す)
julia> res = delete!(dict_test,"b") Dict{String,Int64} with 1 entry: "a" => 20
要素の削除: pop! (削除された要素の値を返す)
julia> dict_test["b"] = 4 4 julia> res = pop!(dict_test,"b") 4
二つの辞書をmergeする(後ろ優先になる)
julia> dict_test Dict{String,Int64} with 3 entries: "c" => 10 "b" => 4 "a" => 20 julia> dict_test2 Dict{String,Int64} with 2 entries: "b" => 200 "a" => 100 julia> println(merge(dict_test,dict_test2)) Dict("c" => 10,"b" => 200,"a" => 100) julia> println(merge(dict_test2,dict_test)) Dict("c" => 10,"b" => 4,"a" => 20)
タプル(Tuple)型
配列や辞書型と同じく複数の値を入れておくことができるコレクションの一つだが、後から内容の変更ができない(イミュータブルと言う).
a = tuple("a","b","c") a = ("a","b","c") #単に括弧でもいい julia> typeof(a) Tuple{String,String,String}
インデックス指定で値を取得できる
julia> a[1] "a"
名前つきタプル(NamedTuple)
julia> test_tuple = (a = 1, b = 2, c = 3) (a = 1, b = 2, c = 3) julia> test_tuple.a #こういう指定ができる 1 julia> test_tuple[3] #もちろんインデックス指定もできる 3
ペア(Pair)型
辞書型の要素となる A => B . 値の更新はできない.
julia> item = "Pencil" => 80 "Pencil" => 80 julia> item.first #firstで最初の要素 "Pencil" julia> item.second #secondで2番目の要素を指定できる 80
Dict()のなかにTuple型の配列を入れる場合でも、要素はPair型となる.
julia> stationary = Dict([("Pencil",80),("Eraser",50),("Ruler",100)]) Dict{String,Int64} with 3 entries: "Ruler" => 100 "Eraser" => 50 "Pencil" => 80 julia> for item in stationary println("$(item.first) : $(item.second)") end Ruler : 100 Eraser : 50 Pencil : 80
集合(Set)型
重複した要素を持たない. 順序がない. 和/積/差/対称差/部分集合/上位集合といった集合演算が使える.
julia> Set([3,1,2,3]) #重複した3は消える. Set([2, 3, 1]) #順番も適当.
配列も入れられる.
julia> [3x+5y for x = 1:3,y=3:4] 3×2 Array{Int64,2}: 18 23 21 26 24 29 julia> Set([3x+5y for x = 1:3,y=3:4]) Set([24, 23, 26, 29, 21, 18])
pushやpopも使える (順番はない).
julia> set_even = Set([2i for i in 1:3]) Set([4, 2, 6]) julia> push!(set_even,8) Set([4, 2, 8, 6]) julia> pop!(set_even) 4 julia> set_even Set([2, 8, 6])
存在確認 (in関数あるいは∈(\inをtab変換)や∋(\ni))
julia> in(6,set_even) true julia> in(5,set_even) false julia> 6 ∈ set_even true julia> set_even ∋ 9 false
和演算
julia> set_a = Set([1,2,3]) Set([2, 3, 1]) julia> set_b = Set([3,4,5]) Set([4, 3, 5]) julia> union(set_a,set_b) Set([4, 2, 3, 5, 1]) julia> set_a ∪ set_b #\cupをtab変換 Set([4, 2, 3, 5, 1])
積
julia> set_a = Set([1,3,4]) Set([4, 3, 1]) julia> set_b = Set([2,3,4,5]) Set([4, 2, 3, 5]) julia> intersect(set_a,set_b) Set([4, 3]) julia> set_a ∩ set_b #\capをtab変換 Set([4, 3])
差
#左辺のみに含まれる項を抽出 julia> setdiff(set_a,set_b) Set([1]) julia> setdiff(set_b,set_a) Set([2, 5]) #どちらかのみに含まれる項を抽出(対称差) julia> symdiff(set_b,set_a) Set([2, 5, 1])
部分集合 (右辺に左辺の値の全てが含まれているかの判定)
julia> set_a = Set([1,2,3]) Set([2, 3, 1]) julia> set_b = Set([1,3]) Set([3, 1]) julia> issubset(set_a,set_b) false julia> set_a ⊆ set_b #\subseteqをtab変換 false julia> set_b ⊆ set_a true
上位集合 (左辺に右辺の値の全てが含まれているかの判定)
julia> set_a ⊇ set_b #\supseteqをtab変換 true
関数
julia> function myfunc(a,b) return a*b end myfunc (generic function with 1 method) julia> myfunc(4,100) 400 #"return"がなくてもいい. julia> function myfunc(a,b) a*b a/b #この場合は最後の式が返される. end myfunc (generic function with 1 method) julia> myfunc(3,2) 1.5 #簡単な書き方もできる. julia> f(a,b)=a*b f (generic function with 1 method) julia> f(3,2) 6
default値(代入がなかった場合にそれを使う)を設定できる.
julia> f(a,b=5)=a*b f (generic function with 2 methods) julia> f(3,2) 6 julia> f(3) 15
引数を可変にする.
julia> function mf(a, b, v...) println(a) println(b) println(v) end mf (generic function with 1 method) julia> mf(3,2) 3 2 () julia> mf(3,2,5,6,7) 3 2 (5, 6, 7)
キーワード引数の指定
julia> function mf(a, b ; item = "Pencil", price = 80) println("$a, $b, $item, $price") end mf (generic function with 2 methods) julia> mf(3,2,item="Note",price=50) 3, 2, Note, 50
引数の型指定
julia> af(a,b::Int64) = a*b af (generic function with 1 method) julia> af(2,3) 6 julia> af(2,3.5) #Float型を渡したのでエラーになる. ERROR: MethodError: no method matching af(::Int64, ::Float64) Closest candidates are: af(::Any, ::Int64) at REPL[55]:1 Stacktrace: [1] top-level scope at REPL[57]:1
戻り値の型指定
julia> af(a,b)::Int64 = a*b af (generic function with 2 methods) julia> af(2,3) 6 julia> af(2,3.5) 7 julia> af(2.5,3.5) ERROR: InexactError: Int64(8.75) Stacktrace: [1] Type at ./float.jl:703 [inlined] [2] convert at ./number.jl:7 [inlined] [3] af(::Float64, ::Float64) at ./REPL[58]:1 [4] top-level scope at REPL[61]:1
複数の戻り値
julia> function myfunc(a,b) return a*b, a/b, 2a+3b end myfunc (generic function with 1 method) julia> myfunc(3,2) (6, 1.5, 12)
受け取る側もカンマ区切りにするとタプルがアンパックされる.
julia> res_1, res_2, res_3 = myfunc(3,2) (6, 1.5, 12) julia> println("$res_1 : $res_2 : $res_3") 6 : 1.5 : 12
タプルで返すのであれば、インデックス指定もできる.
julia> myfunc(3,2)[2] 1.5
無名関数
julia> a -> a^3 + a*3 #10 (generic function with 1 method)
map関数と一緒に使う. もちろん普通に定義した関数も使えるが、簡単な式の場合は無名関数で十分.
#配列を渡す. julia> map(a -> a^3 + a*3, [4, 2.5, -3]) 3-element Array{Float64,1}: 76.0 23.125 -36.0 #タプルを渡す. julia> map(a -> a^3 + a*3, (4, 2.5, -3)) (76, 23.125, -36)
無名関数を変数に格納することもできる.
julia> lambda = a -> a^3 + a*3 #18 (generic function with 1 method) julia> map(lambda, (4, 2.5, -3)) (76, 23.125, -36)
多重ディスパッチ 複数のメソッドを同じ関数に入れることができる.
julia> function mf_dis(a::Int64) return a^3+a*3 end mf_dis (generic function with 1 method) julia> function mf_dis(a::String) println("Argument : $a") end mf_dis (generic function with 2 methods) julia> function mf_dis(a,b) return a*b end mf_dis (generic function with 3 methods)
渡す引数によってどれを実行するか選択できる.
julia> mf_dis(2) 14 julia> mf_dis("test") Argument : test julia> mf_dis(2,4) 8
構造体
イミュータブル(更新不可)のstuructと ミュータブル(更新課)のmutable structがある.
julia> struct Kitchenware item price::Int64 stock end
インスタンスを作成する.
julia> Kitchenware1 = Kitchenware("Bowl",100,10) Kitchenware("Bowl", 100, 10)
型は構造体名になる.
julia> typeof(Kitchenware1) Kitchenware
メンバの型が宣言と合わないとエラーになる.
julia> Kitchenware2 = Kitchenware("Ladle",150.2,5) ERROR: InexactError: Int64(150.2) Stacktrace: [1] Type at ./float.jl:703 [inlined] [2] convert at ./number.jl:7 [inlined] [3] Kitchenware(::String, ::Float64, ::Int64) at ./REPL[82]:2 [4] top-level scope at REPL[85]:1
値の参照は.メンバ名でする.
julia> Kitchenware1.item
"Bowl"
mutable struct
julia> mutable struct Tableware item::String price::Int64 stock::Int64 end julia> tableware1 = Tableware("Cup",120,30) Tableware("Cup", 120, 30) julia> tableware1.item "Cup" julia> tableware1.price 120
値の更新ができる.
julia> tableware1.stock = 29 29
構造体の配列を作成する.
julia> arr_kitchenware = Array{Kitchenware}(undef,3) 3-element Array{Kitchenware,1}: #undef #undef #undef
julia> arr_kitchenware[1] = Kitchenware("Bowl",100,10) Kitchenware("Bowl", 100, 10) julia> arr_kitchenware[2] = Kitchenware("Ladle",150,5) Kitchenware("Ladle", 150, 5) julia> arr_kitchenware[3] = Kitchenware("Flying pan",3500,6) Kitchenware("Flying pan", 3500, 6) julia> arr_kitchenware[3].item "Flying pan"
宣言した要素数以上入れようとするとエラーになる.
julia> arr_kitchenware[4] = Kitchenware("Kettle",1000,3) ERROR: BoundsError: attempt to access 3-element Array{Kitchenware,1} at index [4] Stacktrace: [1] setindex!(::Array{Kitchenware,1}, ::Kitchenware, ::Int64) at ./array.jl:766 [2] top-level scope at REPL[97]:1
push!関数なら要素の追加ができる.
julia> push!(arr_kitchenware, Kitchenware("Kettle",1000,3)) 4-element Array{Kitchenware,1}: Kitchenware("Bowl", 100, 10) Kitchenware("Ladle", 150, 5) Kitchenware("Flying pan", 3500, 6) Kitchenware("Kettle", 1000, 3)
簡単な形式.
julia> mutable struct Tableware item::String price::Float64 stock::Int64 end julia> arr_tableware = [Tableware("Cup",108.5,30),Tableware("Spoon",210.1,50),Tableware("Dish",1041.3,10)] 3-element Array{Tableware,1}: Tableware("Cup", 108.5, 30) Tableware("Spoon", 210.1, 50) Tableware("Dish", 1041.3, 10)