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より大きくない")
53より大きい

#if-elseif-elseみたいにできる
julia> println(5 > 3 ? 5==3 ? "5は3に等しい" : "5は3より大きい" : "5は3より大きくない")
53より大きい

#関数の定義にも使える($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)
1050 より大きくない

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

キーのイテレータ: keys(iterator)

julia> keys(dict_test)
Base.KeySet for a Dict{String,Int64} with 2 entries. Keys:
  "b"
  "a"

値のイテレータ: values(iterator)

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)