Tupleは、多くの点でVector(1次元のarray)とよく似ています。
ただし、いくつか重要な違いがあります。
[ ]ではなく、丸括弧( )で書きます。ただし、意味が曖昧でない場合は、丸括弧を省略できます。イミュータブルであることにより、コンパイラーによる最適化がより多く行われ、タプルはベクトルよりも性能が高くなります。そのため、可変である必要がない場合は、タプルを選ぶとよいでしょう。
julia> t = (3, 5.2, "xyz")
(3, 5.2, "xyz")
# Non-homogeneous:
julia> dump(t)
Tuple{Int64, Float64, String}
1: Int64 3
2: Float64 5.2
3: String "xyz"
julia> t[2]
5.2
# Immutable:
julia> t[2] = 7.3
ERROR: MethodError: no method matching setindex!(::Tuple{Int64, Float64, String})
Tuple()というコンストラクターもあり、これは任意の反復可能なコレクションをタプルに変換します。便利なことに、文字列は文字の反復可能なコレクションとして扱われます。
julia> Tuple("Julia")
('J', 'u', 'l', 'i', 'a')
どのタプルでも、インデックスで要素にアクセスしたり、ループで要素を順に取り出したりできます。
数値だけからなるタプルは、配列とまったく同じように、sum()などの数学関数で使うこともできます。
タプルは、多重代入を使うことで個々の要素にアンパックできます。
必要のない要素には、ダミー変数としてアンダースコア_を使います。
julia> tup = (1, "Julia", true)
(1, "Julia", true)
julia> num, name, _ = tup
(1, "Julia", true)
julia> uppercase(name), 2num
("JULIA", 2)
Pythonを使っている人なら、この多重代入の構文にはとても馴染みがあるでしょう。
Tupleは値だけを持ちます。
NamedTupleは、それぞれの値に名前を組み合わせたものです。
個々のフィールドには、ドット記法でアクセスできます。
julia> nt = (a = 1, b = 7.3)
(a = 1, b = 7.3)
julia> dump(nt)
@NamedTuple{a::Int64, b::Float64}
a: Int64 1
b: Float64 7.3
julia> nt.b
7.3
名前は内部的にはSymbol(イミュータブルな型で、コロン:が先頭に付きます)として保持されるため、別の構文も使えます。
julia> nt[:b]
7.3
名前(「キー」とも呼ばれます)だけ、あるいは値だけを別々に取り出すのは簡単です。
julia> nt
(a = 1, b = 7.3)
julia> keys(nt)
(:a, :b)
julia> values(nt)
(1, 7.3)
名前付きタプルを繰り返し処理しても取り出せるのは_値_だけで、_名前_は無視されることに注意してください。
タプルは(名前付きかどうかに関わらず)、構造化されたデータを関数に渡したり、関数から受け取ったりするためによく使われる方法です。 このような用途ではイミュータブルであることが役立ち、データの安全性を確保し、コンパイラーによるより積極的な最適化を可能にします。
AzaraとRuiは、海賊をテーマにした宝探しに挑むチームメイトです。 一人は地図の座標が付いた宝物のリストを、もう一人は地図の座標が付いた場所の名前のリストを持っています。 二人には、出発地点に YOU ARE HERE と印を付けた白地図も渡されています。
| Azaraのリスト | Ruiのリスト | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
しかし、少し困ったことがあります。Azaraの座標は、Ruiのものとは書式や並び順が違うようなのです。そのため、どの宝物がどの場所に対応するのかを知るには、二人は何度もリストを見比べなければなりません。 二人は駆け出しのJuliaプログラマーで、宝探しの情報をうまく整理するための小さなプログラム(実際にはいくつかの関数です)を書くのを手伝ってほしいと、助けを求めてきました。
Azaraのリストから(treasure, coordinate)のペアを受け取り、そこから取り出した地図の座標だけを返すget_cooordinate()関数を実装してください。
julia> get_cooordinate( ("Scrimshaw Whale's Tooth", "2A") )
"2A"
"2A"という形式の座標を受け取り、('2', 'A')という形式のタプルを返すconvert_coordinate()関数を実装してください。
julia> convert_coordinate("2A")
('2', 'A')
(treasure, coordinate)のペアと(location, coordinate, quadrant)のレコードを受け取り、それぞれの座標を比較するcompare_records()関数を実装してください。
座標が「一致」すれば**trueを、一致しなければfalse**を返します。
正確に比較するために、必要に応じて座標を整形し直してください。
julia> compare_records(("Brass Spyglass", "4B"), ("Seaside Cottages", ('1', 'C'), "blue"))
false
julia> compare_records(("Model Ship in Large Bottle", "8A"), ("Harbor Managers Office", ('8', 'A'), "purple"))
true
Azaraのリストから(treasure, coordinate)のペアを、Ruiのリストから(location, coordinate, quadrant)のレコードを受け取り、座標が一致すれば(coordinate, location, quadrant, treasure)を返すcreate_record()関数を実装してください。
座標が一致_しなければ_、空のタプルを返します。 正確に比較するために、必要に応じて座標を整形し直してください。
julia> create_record(("Brass Spyglass", "4B"), ("Abandoned Lighthouse", ('4', 'B'), "Blue"))
("4B", "Abandoned Lighthouse", "Blue", "Brass Spyglass")
julia> create_record(("Brass Spyglass", "4B"), ("Seaside Cottages", ('1', 'C'), "Blue"))
()