今回はIndexSet
について。
Listの並び替えや削除処理の際によく出てくるIndexSet
。
このIndexSet
は理解して使えるようになるまでだいぶ苦労したので、備忘録として理解したことをまとめておこうと思う。
IndexSetとは?
IndexSet
は整数の集合を効率的に管理するための構造体だ。
複数の数字をまとめて管理するための便利な「箱」みたいなイメージを持つと理解しやすいかもしれない。
IndexSet
は特にList
での処理など複数の要素をまとめて操作する場合に使われることが多く、削除や並び替えといった処理で活躍する。
IndexSetの特徴
IndexSet
は下記の特徴がある。
- 0以上の整数のみを格納できる=負の整数は不可
- 整数の重複は許されない=ユニークな値を保持する(Setの特徴と一緒)
- 連続した整数の範囲を効率的に管理するよう設計
- 配列やコレクションのインデックス操作に便利
上記特徴があるため、例えば、[1,2,2,3,4] という値をIndexSet
型の変数に格納すると重複は無視されて、[1,2,3,4]という値が格納される。
Listでの使用例
前述の通りIndexSet
はListでの並べ替えや削除処理でよく使われる。
具体的にListのシンプルな削除処理でどのようにIndexSet
が活用されるのかを簡単なサンプルコードで確認していこう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import SwiftUI struct ContentView: View { @State private var items = ["Apple", "Banana", "Cherry", "Strawberry", "Pineapple"] var body: some View { List { ForEach(Array(items.enumerated()), id: \.element) { index, item in HStack { Text("\(index).") // インデックス Text(item) // アイテム名 } } .onDelete(perform: deleteItems) } } private func deleteItems(at offsets: IndexSet) { // 対象の削除数 print("削除対象数: \(offsets)") for offset in offsets { // 実際に削除されたインデックスを表示 print("削除対象のインデックス番号: \(offset)") } items.remove(atOffsets: offsets) } } |
上記はシンプルな果物リストのコードだ。
下記のようにListの各行にその行のインデックスと果物名が表示している。
このリストを左にスワイプしてDeleteボタンを押すと対象の果物の行が削除される処理を組み込んでいる。
1 2 3 4 5 6 7 8 9 | private func deleteItems(at offsets: IndexSet) { // 対象の削除数 print("削除対象数: \(offsets)") for offset in offsets { // 実際に削除されたインデックスを表示 print("削除対象のインデックス番号: \(offset)") } items.remove(atOffsets: offsets) } |
この削除処理の引数に使われているのが、IndexSet
型のoffsetsだ。
行を削除する際に、その行のindex番号が indexSet([~]) という形で offsetsに格納される
実際にListの3行目の 2.Cherry を削除する際の流れとoffsetsの値は下記の通りだ。
print文でIndexSet
型の変数を出力すると、対象が何個あるかが表示される。
上記例の場合「削除対象数:1 indexes」の部分だ。
今回は3行目のみを削除対象にしたので、対象は1つとなる。
IndexSet
型の変数に具体的にどんな整数が入っているかを確認したい場合は、下記のようにfor文で取り出してあげる必要がある。
1 2 3 4 5 6 7 8 9 | private func deleteItems(at offsets: IndexSet) { // 対象の削除数 print("削除対象数: \(offsets)") for offset in offsets { // 実際に削除されたインデックスを表示 print("削除対象のインデックス番号: \(offset)") } items.remove(atOffsets: offsets) } |
今回は3行目を削除したので、その行のインデックス番号である2が格納され、print文で 2 と出力された。
今回は単一の値を格納する例だったが、IndexSet
型の変数には複数の整数を格納することも可能だ。
この例のように、実際にデバックコードでIndexSet
型の変数に格納される値を出力しながら確認するとだいぶ理解しやすくなるはずだ。
まとめ
本記事で紹介したIndexSet
の要点は下記の通りだ。
- 0以上の整数のみを格納できる=負の整数は不可
- 整数の重複は許されない=ユニークな値を保持する(Setの特徴と一緒)
- 単一の値だけでなく、複数の整数を格納可能
- Listの削除処理や並べ替え処理に便利
- デバックコードで実際にindexSetにどんな値が入るかを出力するシンプルなプログラムを動かしながら確認するのが理解への近道
indexSetの理解に苦労している人の参考に少しでもなれば嬉しい。