1000までの非負の整数をすべて手に入れたいとします。 それを1つずつ配列に入力しなければならないとしたら、ばかげていますよね。
そこで登場するのが、range型です。
julia> 0:1000
0:1000
julia> typeof(0:1000)
UnitRange{Int64}
rangeは非常によく使われます。入力を省くためだけでなく、関数の戻り値としても使われます。
rangeはベクトルでは_ありません_。
シーケンスを生成するための一連の指示にすぎません(「遅延」評価、つまり「イテレーター」です)。
rangeをベクトルとして使いたいときは、collect()関数で変換します。
julia> collect(0:5)
6-element Vector{Int64}:
0
1
2
3
4
5
ステップ幅も指定できます。この例では0.3です。
julia> collect(1.0:0.3:2.0)
4-element Vector{Float64}:
1.0
1.3
1.6
1.9
つまり、構文はstart:stepsize:stopです。
整数の例で見たように、両端の値はどちらも_含まれます_。
ステップ幅がstop - startをちょうど割り切れない場合、最後の要素はstopを超えないようになります。
rangeには数値以外のシーケンスも使えます。
最も単純な例はASCII文字です。
julia> 'a':'d'
'a':1:'d'
julia> typeof('a':'d')
StepRange{Char, Int64}
julia> collect('a':'d')
4-element Vector{Char}:
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase)
Char型については、別のコンセプトで詳しく扱います。
今は、シングルクォートで囲んだ1文字だと考えておきましょう。
rangeのための関数と演算子rangeの両端はfirst()とlast()で確認できます。
r = 1:10 # => 1:10
first(r) # => 1
last(r) # => 10
ベクトルのインデックス指定には、整数のrangeとベクトルの両方が使えます。
nums = collect(10.0:50.0)
nums[3:2:7] # gives [12.0, 14.0, 16.0]
nums[ [3, 5, 7] ] # also gives [12.0, 14.0, 16.0]
チェスの愛好家なら、自分だけのバージョンのゲームを書いてみたくなるでしょう。確かに、オンラインにはすでにたくさんのチェスの実装が出回っていますが、自分で作るものは世界に一つだけのものです!
でも、想像を膨らませる前に、まずは基本を押さえる必要があります。ボードの生成から始めましょう。
チェスボードの各マスは、文字と数字のペアで識別されます。マスの縦の列はファイルと呼ばれ、AからHまでのラベルが付いています。マスの横の行はランクと呼ばれ、1から8までの番号が付いています。
rank_range()関数を実装しましょう。1から8までの整数の範囲を返します。
julia> rank_range()
# output omitted
file_range()関数を実装しましょう。
大文字のAから大文字のHまでの文字の範囲を返します。
julia> file_range()
# output omitted
ranks()関数を実装しましょう。1から8までの整数のベクトルを返します。
ベクトルを手で書かず、rank_range()関数が返す範囲から生成しましょう。
julia> ranks()
[1, 2, 3, 4, 5, 6, 7, 8]
files関数を実装しましょう。'A'から'H'までの文字のベクトルを返します。
ベクトルを手で書かず、file_range()関数が返す範囲から生成しましょう。
julia> files()
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']