SwiftUIの基本を身につけたい方はこちら

【Xcode/Swift】タプルの使い方について徹底解説~タプルの配列・ネスト・関数・入れ替えなど~

この記事では、簡単に理解できて便利なタプルを紹介していきたいと思います。

タプル(Tuple)とは?

二つ以上の異なる型の値を一つの値としてまとめることができる値のことです。

例えば、以下の画像の名前と色を変数で持つプログラムがあります。

struct ContentView: View {
    let imageName = "globe"
    let imageColor = Color.red
    
    var body: some View {
        Image(systemName: imageName)
            .foregroundColor(imageColor)
    }
}

これをタプルを使ってわかりやすくすると、

struct ContentView: View {
    let imageData = ("globe", Color.red)
    
    var body: some View {
        Image(systemName: imageData.0)
            .foregroundColor(imageData.1)
    }
}

構造体とか作るまでもない変数は、このタプルにしてまとめるのが一番良いかと思います。

タプルにはできない

タプルは配列と違って要素を追加したり削除したりすることはできません。

タプルの宣言

基本的な使い方

let pet = ("太郎", 12, 20)

print("名前:\(pet.0)") // 名前:太郎
print("年齢:\(pet.1)") // 年齢:12
print("体重:\(pet.2)") // 体重:20

左から0,1,2…とタプルの中の値にアクセスできます。

値にキーワードをつける

let pet = (name: "太郎", age: 12, weight: 20)
print("名前:\(pet.name)") // 名前:太郎
print("年齢:\(pet.age)") // 年齢:12
print("体重:\(pet.weight)") // 体重:20

0,1,2で値を扱うと、実装している最中に頭のなかで0はあれで1はあれというふうに考えながら実装しなければなりません。

そこで、上記のコードのようにタプルの中のそれぞれの値にキーワードをつけることで、視覚的にもわかりやすく良いコードになります。

ちなみにキーワードをつけてもインデックスでも取得できます。

型を指定する

let pet: (String, Int, Double) = ("太郎", 12, 20)
print("名前:\(pet.0)") // 名前:太郎
print("年齢:\(pet.1)") // 年齢:12
print("体重:\(pet.2)") // 体重:20.0

(型名, 型名, 型名)というふうにすればその値に型を指定することができます。

値にキーワードをつけて型も指定する

let pet: (name: String, age: Int, weight: Double) = (name: "太郎", age: 12, weight: 20)
print("名前:\(pet.name)") // 名前:太郎
print("年齢:\(pet.age)") // 年齢:12
print("体重:\(pet.weight)") // 体重:20.0

それぞれの値にキーワードをつける&型名を記載する際は、型名にもキーワードをつけなければなりません。

それぞれ別の変数にする

let (name, age, weight) = ("太郎", 12, 20.0)
print("名前:\(name)") // 名前:太郎
print("年齢:\(age)") // 年齢:12
print("体重:\(weight)") // 体重:20

この方法が一番シンプルなタプルを使った書き方ですが、nameがなんのnameなのかがわからなくなってしまいます。なので、これだったら個別に宣言する形とそこまで変わらないので、、

ちなみに、letで宣言する変数の数と、代入する値の数が同じでなければエラーになります。使わない値は_を使いましょう。

ネストしたタプル

let pet = (name: "太郎", age: 12, weight: 20, chilled: (name: "二郎", age: 2, weight: 5))
print("名前:\(pet.name)") // 名前:太郎
print("年齢:\(pet.age)") // 年齢:12
print("体重:\(pet.weight)") // 体重:20
print("子供の名前:\(pet.chilled.name)") // 子供の名前:二郎
print("子供の年齢:\(pet.chilled.name)") // 子供の年齢:2
print("子供の体重:\(pet.chilled.name)") // 子供の体重:5

タプルの配列

配列に入れることも可能です。

let pet: [(name: String, age: Int, weight: Double)] = [
    (name: "太郎", age: 12, weight: 20),
    (name: "二郎", age: 2, weight: 5),
    (name: "三郎", age: 1, weight: 3)
]
print("名前:\(pet[0].name)") // 名前:太郎
print("年齢:\(pet[0].age)") // 年齢:12
print("体重:\(pet[0].weight)") // 体重:20.0

タプルの値変更

タプルは値の変更が可能です。

値をそれぞれ変更

var pet = (name: "太郎", age: 12, weight: 20)
pet.name = "二郎"
pet.age = 5
pet.weight = 10
print("名前:\(pet.name)") // 名前:二郎
print("年齢:\(pet.age)") // 年齢:5
print("体重:\(pet.weight)") // 体重:10

まとめて変更

var pet = (name: "太郎", age: 12, weight: 20)
pet = ("二郎", 5, 10)
print("名前:\(pet.name)") // 名前:二郎
print("年齢:\(pet.age)") // 年齢:5
print("体重:\(pet.weight)") // 体重:10

タプル同士で入れ替え

タプルの便利なところとして、入れ替えが簡単にできることです。

var player1 = "先行"
var player2 = "後行"
(player1, player2) = (player1, player2)
print("player1:\(player1)") // 後行
print("player2:\(player2)") // 先行

キーワードが異なるタプル同士は代入できない

var pet = (name: "太郎", age: 12, weight: 20)
var pet1 = (name: "二郎", age: 10, weight: 15)
var pet2 = (n: "三郎", a: 5, w: 10)

pet = pet1 // 代入できる
pet = pet2 // エラー

上記の場合だと、petnameageweightなのに、pet2nawです。このようにキーワードが異なるとエラーになってしまいます。

関数の戻り値としてタプルを使う

関数で複数の値を返したい時にタプルを使うと便利です。

func BMI(tall: Double, weight: Double) -> (Double, Double) {
    let ideal = 22.0
    let t2 = tall * tall / 10000.0
    let index = weight / t2
    let target = ideal * t2
    return (index, target)
}

キーワードをつけることもできます。

func BMI(tall: Double, weight: Double) -> (index: Double, target: Double) {
    let ideal = 22.0
    let t2 = tall * tall / 10000.0
    let index = weight / t2
    let target = ideal * t2
    return (index, target)
}

タプルの比較

タプル同士で比較することもできます。

print((10, 20, 30) > (10, 25, 30)) // false
print((10, 20, 40) > (10, 20, 30)) // true

ちなみに、左から順序に比較していきます。

おまけ

この記事に書かれていることが面白かったです。

すべての値は「値が1つだけのTuple」らしい。

この2行は同じ意味
var txt = "てきすと"
var (txt) = ("てきすと")
なので 変数名.0 でアクセスできる。

変数名.0
var txt = "てきすと"
println(txt.0) // -> てきすと
txt.0 = "テキスト"
println(txt) // -> テキスト
これ リテラル.0 もいけた。

リテラル.0
println("text".0) // -> text
println((0).0) // -> 0
println(true.0) // -> true
そしてこれ

0の連鎖
var txt = "てきすと"
println(txt) // -> てきすと
println(txt.0) // -> てきすと
println(txt.0.0) // -> てきすと
println(txt.0.0.0) // -> てきすと
txt.0.0.0.0 = "テキスト"
println(txt) // -> テキスト

引用元:Qiita-(SwiftのTupleを使う – Qiita)

いつも宣言している値は、値が一つのタプルだったというわけです。