Julia でいろんな繰り返し処理・イテレーションを書く
概要
Julia では(邪道を含めて)いろんな繰り返し処理・イテレーションの書き方ができます。思いつく限りの書き方を列挙していきます。次のイテラブルなオブジェクトを考えます。
xs = "あいうえお"
一覧
for =
一番最初に習う書き方です。C 風です。
for x = xs
println(x)
end
for in
次に習う書き方です。一番一般的です。Python 風です。
for x in xs
println(x)
end
for ∈
LaTeX で言うところの \in です。REPL でも \in で入力します。数学風です。
for x ∈ xs
println(x)
end
while
for よりも細かい制御をする場合には whlie が必要になります。一般には iterate を使って返却値が nothing になるまで処理をします。
i = iterate(xs)
while !isnothing(i)
x, state = i
println(x)
i = iterate(xs, state)
end
goto
一般には多重ループから抜け出すときぐらいしか使わない @goto ですが、もちろん繰り返し処理にも使えます。古い秘伝のスパゲティソースをそのまま移植したいときにどうぞ。
let
i = iterate(xs)
@label loop
x, state = i
println(x)
i = iterate(xs, state)
if !isnothing(i)
@goto loop
end
end
recursive
goto の代わりに関数の再帰でも書けます。関数の書き方にも色々ありますが、それは省略します。
function f(xs, i)
if isnothing(i)
nothing
else
x, state = i
println(x)
i = iterate(xs, state)
f(xs, i)
end
end
i = iterate(xs)
f(xs, i)
foreach
単純な処理しかしない場合には for を使うよりも短くなります。ちょっと関数型言語風に書きたいときにどうぞ。後述する map と違って値は返しません(nothing を返す)。
foreach(println, xs)
map
関数型風に書くときに便利な map です。一般的な iterable に対してイテレートするには collect する必要があります。foreach と違って、値を返します。もちろんこの println の場合に返ってくるのは役に立たない型 Vector{Nothing} の配列です。
map(println, collect(xs))
foreach do
do を使うと第一引数として渡す関数の処理を書き下すことができます。foreach に渡す関数がその場でしか使わない場合にどうぞ。for と役割は被っています。
foreach(xs) do x
println(x)
end
map do
さっきの map 版です。for や foreach では値を返せない一方で、こちらでは値を返せるので役割が被っているということはないです。
map(collect(xs)) do x
println(x)
end
comprehension for =
内包 (comprehension) 記法というやつです。値を返します。
[println(x) for x = xs]
comprehension for in
さっきの in 版です。Python 風です。
[println(x) for x in xs]
comprehension for ∈
さっきの ∈ 版です。もともと数学の記法(例えば、
[println(x) for x ∈ xs]
fold
この辺から、一般の手続き的な処理をするには邪道です。関数型言語でよく見るやつです。値を返します。
foldl((x, y) -> println(y), xs, init=nothing)
mapfold
一般のイテレート処理をするには邪道だと思います。数式などで使いましょう。値を返します。
mapfoldl(println, (x, y) -> nothing, xs, init=nothing)
accumulate
邪道です。
accumulate((x, y) -> println(y), xs, init=nothing)
Iterators.map
map の 遅延評価版です。
collect(Iterators.map(println, xs))
Iterators.accumulate
accumulate の 遅延評価版です。
collect(Iterators.accumulate((x, y) -> println(y), xs, init=nothing))
まとめ
合計 18 種類ものイテレート処理の書き方を見てきました。使ったことのあるやつもあればないやつもありました。他にもあったら教えて下さい。
Discussion