ループには大きく分けて2つの種類があります。
どちらもJuliaで書くことができますが、2つ目のほうがよく使われるかもしれません。
whileループ繰り返す回数があらかじめわからないような問題には、Juliaのwhileループが使えます。
基本の形はとてもシンプルです。
while condition
do_something()
end
この場合、conditionがtrueでなくなるまで、プログラムはループを回り続けます。
ループから途中で抜ける方法は2つあります。
breakを使うとループを抜け、ループのendの次の行から実行が続きます。return xは現在の関数の実行を終了し、戻り値xを呼び出し元に返します。こうした方法があると、while true ... endで「無限」ループを作り、ループ本体の中で停止条件を見つけてbreakやreturnを実行する、という書き方が便利なこともあります。
一番わかりやすい例は、範囲をループすることです。
何かを10回行いたいときは、次のように書きます。
for n in 1:10
do_something(n)
end
現在の繰り返しがある条件を満たさないときは、continueで次の繰り返しへすぐに進むことができます。
for n in 1:10
if is_useless(n)
continue
end
# we decided this iteration could be useful
do_something_slow(n)
end
もっと短く書くなら、ifブロックをis_useless(n) && continueに置き換えることもできます。
ほかにもさまざまなコレクションをループできます。配列の要素、文字列の文字、辞書のキーなどです。
ここまでの例では範囲1:10をループしていて、値がそのままループのインデックスにもなっています。
より一般的には、値だけでなくインデックスが必要になることもあります。
そういうときはeachindex()関数を使います。たとえばfor i in eachindex(my_array) ... endのように書きます。
友人のLi Meiは、おいしいミックスフルーツジュースを売るジュースバーを営んでいます。Li Meiのお店によく通っていたところ、自分のプログラミングスキルを使って友人の仕事を楽にしてあげられることに気づきました。そこで、そのスキルを活かしてLi Meiの仕事を手伝うことにしました。
Li Meiは、お客さんがメニューから注文したジュースを待つ時間を、あらかじめ伝えるのが好きです。ジュースを混ぜるのにかかる時間はそれぞれ違うので、正確な数字を覚えておくのは大変です。
"Pure Strawberry Joy"は0.5分、"Energizer"と"Green Garden"はそれぞれ1.5分、"Tropical Island"は3分、"All or Nothing"は5分かかります。
その他の飲み物(例えば、特別メニュー)については、準備に2.5分かかると考えてかまいません。
友人を助けるために、メニューにあるジュースを入力として受け取り、その飲み物を混ぜるのにかかる分数を返す関数time_to_mix_juiceを書いてみましょう。
julia> time_to_mix_juice("Tropical Island")
3
julia> time_to_mix_juice("Berries & Lime")
2.5
Li Meiが作る飲み物の多くには、材料として、あるいは飾りとして、ライムのくし切りが入っています。 そのため、朝シフトが始まるときには、これから始まる1日のために、ライムのくし切りの容器がいっぱいになっているようにしておく必要があります。
Li Meiが切る必要のあるライムのくし切りの数と、手元にある丸ごとのライムの在庫を表す配列を受け取る関数limes_to_cutを実装しましょう。
"small"のライムからは6つのくし切り、"medium"のライムからは8つのくし切り、"large"のライムからは10のくし切りが取れます。
Li Meiはいつも、リストに現れる順番どおり、最初のライムから切っていきます。
必要な数のくし切りに達するか、ライムがなくなるまで切り続けます。
Li Meiは、あらかじめ何個のライムを切る必要があるのかを知りたいと思っています。
limes_to_cut関数は、切る必要のあるライムの数を返すようにします。
julia> limes_to_cut(25, ["small", "small", "large", "medium", "small"])
4
Li Meiは、お客さんが待っている注文を混ぜるのにどれくらい時間がかかるかを把握しておくのが好きです。
注文の行列を受け取り、混ぜる時間のベクトルを返すorder_times関数を実装しましょう。
julia> order_times(["Energizer", "Tropical Island"])
[1.5, 3.0]
Li Meiはいつも15時まで働きます。 その後は、従業員のDmitryが引き継ぎます。 Li Meiのシフトが終わる時点で、注文はされたけれどまだ準備されていない飲み物が残っていることがよくあります。 Dmitryは、残っているジュースを準備します。
引き継ぎを楽にするために、Li Meiのシフトに残っている分数と、注文はされたけれどまだ準備されていないジュースの配列を受け取る関数remaining_ordersを実装しましょう。
この関数は、Li Meiが勤務時間の終わりまでに準備を始められない注文を返すようにします。
シフトに残っている時間は、常に0より大きくなります。 準備するジュースの配列が空になることはありません。 さらに、注文は配列に現れる順番で準備されます。 Li Meiが何かジュースを混ぜ始めたら、少し長く働くことになっても、必ず最後まで作り終えます。 Dmitryが対応する必要のある注文が1つも残っていない場合は、空のベクトルを返すようにします。
julia> remaining_orders(5, ["Energizer", "All or Nothing", "Green Garden"])
["Green Garden"]