【Swift】enumeratedの使い方!配列のインデックスを取得する

この記事からわかること
- Swiftで配列のインデックスを取得する方法
- enumeratedメソッドの使い方
- ArraySliceを扱う際の注意点
- zipメソッドの使い方
index
[open]
\ アプリをリリースしました /
環境
- Xcode:15.0.1
- iOS:17.1
- Swift:5.9
- macOS:Sonoma 14.1
enumeratedメソッドで配列のインデックスを取得する
func enumerated() -> EnumeratedSequence<Self>
Swiftのenumerated
はコレクション内の要素とインデックスをペアとして返すメソッドです。返り値のEnumeratedSequence
型は要素(x)とインデックス(n)をペアにした(n,x)
型のシーケンスです。
let fruits = ["Apple", "Banana", "Orange"]
for (index, fruit) in fruits.enumerated() {
print("Index: \(index), Fruit: \(fruit)")
}
正確にはインデックスではない
公式リファレンスを読んでいると「ペアの整数部分は列挙のカウンターであり、必ずしもインデックスではない」と記述されておりました。
When you enumerate a collection, the integer part of each pair is a counter for the enumeration, but is not necessarily the index of the paired value.
引用:公式リファレンス
例えばSet
型のコレクションの場合、enumerated
ではNo exact matches in call to subscript
というエラーになります。
let names: Set = ["Sofia", "Camilla", "Martina", "Mateo", "Nicolás"]
for (i, _) in names.enumerated() {
print(names[i]) // No exact matches in call to subscript
}
このインデックスを取得したい場合はzip
メソッドを使用してねと公式に記述されていました。
let names: Set = ["Sofia", "Camilla", "Martina", "Mateo", "Nicolás"]
for (i, _) in zip(names.indices, names) {
print(names[i])
}
また普通の配列でもdropFirst
などを使用た返り値がArraySlice
型になる場合は範囲外のエラーになってしまいます。
let fruits = ["Apple", "Banana", "Orange"].dropFirst()
for (index, _) in fruits.enumerated() {
print(fruits[index]) // Index out of bounds
}
これはArraySlice
自体の特徴で元になった配列のindexを保持するコレクション型だからです。そのため必ず[0]
が存在するわけではないからであり、enumerated
は対象のコレクションのインデックスとは関係ないただの個数のカウンターなので範囲外でエラーになってしまうようです。
公式リファレンス:Slices-Maintain-Indices
Array(配列)に変換する
enumerated
メソッドの返り値はEnumeratedSequence
型になるので配列などに戻すにはmap
でelement
プロパティの配列を作り直せばOKです。
let fruits = ["Apple", "Banana", "Orange"]
let enumList = fruits.enumerated()
print(type(of: enumList)) // EnumeratedSequence<Array<String>>
let array = enumList.map({ $0.element })
print(type(of: array)) // Array<String>
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。