【Swift】構造体の要素を検索してインデックスを取得する方法!
この記事からわかること
- Swiftで構造体の要素インデックスを取得するには?
- firstやfilter、firstIndexの使い方
- Equatableプロトコルとは?
- 構造体やクラスを比較する方法
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Xcode:15.0.1
- iOS:17.0
- watchOS:10.0
- Swift:5.9
- macOS:Sonoma 14.1
Swiftで構造体を扱うときにデータ内の特定の要素やそのインデックス番号を検索して取得する方法をまとめていきます。
構造体の中の要素を検索して取得する
扱う[構造体]
[
Language(name : "HTML", version : 5),
Language(name : "CSS", version : 3),
Language(name : "Swift", version : 5)
]
配列内に特定の構造体の要素が格納されている際に指定の値を持つ要素を取得するにはfirst
メソッドまたはfilter
メソッドを使用します。
両者の違いは返り値として取得できる要素数の違いです。first
メソッドは最初にマッチした要素1つ、filter
メソッドはマッチした要素全てを返します。
firstメソッド
返り値は条件にマッチした要素1つ。ない場合はnil
を返します。
array.first(where: { 条件式 })
filterメソッド
返り値は条件にマッチした要素全て。ない場合は空の配列を返します。
array.filter{ 条件式 }
firstメソッドの使い方
first
メソッドは配列に対して使用できるメソッドでfirst(where:)
形式を使えば要素の値に条件式を渡してマッチする要素を検索することができます。
クロージャ内では$0
で疑似的な要素(構造体)に参照することができ、さらにプロパティにはドットシンタックスを使って$0. プロパティ
でアクセスできます。
条件で検索してマッチする構造体を取得
var all = [
Language(name : "HTML", version : 5),
Language(name : "CSS", version : 3),
Language(name : "Swift", version : 5)
]
var searchLanguage = all.first(where: { $0.version < 4 })
// Optional(__lldb_expr_94.Language(name: "CSS", version: 3))
またwhere
を省略して以下のように記述することも可能です。
var searchLanguage2 = all.first {
$0.version < 4
}
filterメソッドの使い方
filter
メソッドの使い方はfirst
メソッドとは異なり条件式を渡す際のwhere
は必要ありません。そのままクロージャの中に条件を指定しマッチした要素がコレクション形式で取得できます。
条件で検索してマッチする構造体を取得
var all = [
Language(name : "HTML", version : 5),
Language(name : "CSS", version : 3),
Language(name : "Swift", version : 5)
]
var searchLanguage = all.filter({ $0.version > 4 })
// [__lldb_expr_5.Language(name: "HTML", version: 5), __lldb_expr_5.Language(name: "Swift", version: 5)]
以下の形式でもOKです。
var searchLanguage2 = all.filter {
$0.version > 4
}
構造体の中の要素を検索してインデックスを取得する
配列内に特定の構造体の要素が格納されている際に指定の値(構造体)を持つ要素インデックスを取得するにはfirstIndex
メソッドを使用します。
array.firstIndex(of:)
firstIndex
メソッドはfirstIndex(of:)
形式で使用します。引数of
には値を渡し、その値と完全に一致する要素のインデックス番号
を返します。
条件で検索してマッチする構造体を取得
var all = [
Language(name : "HTML", version : 5),
Language(name : "CSS", version : 3),
Language(name : "Swift", version : 5)
]
var item = Language(name : "Swift", version : 5)
var index = all.firstIndex(of :item)
しかし上記のコードでは以下のようなエラーが発生してしまいます。
Referencing instance method 'firstIndex(of:)' on 'Collection' requires that 'Language' conform to 'Equatable'
// 翻訳:'Collection'でインスタンスメソッド'firstIndex(of :)'を参照するには、'Language'が'Equatable'に準拠している必要があります
これを解決するには構造体がEquatable
プロトコルに準拠している必要があります。
struct Language:Equatable{
var name:String
var version:Int
}
var all = [
Language(name : "HTML", version : 5),
Language(name : "CSS", version : 3),
Language(name : "Swift", version : 5)
]
var item = Language(name : "Swift", version : 5)
var index = all.firstIndex(of :item)!
print(all[index]) // Language(name: "Swift", version: 5)
Equatableプロトコルとは?
Equatable
プロトコルはオブジェクトを比較可能にできるようにするプロトコルです。
比較するプロパティを変更する
Equatable
プロトコルを準拠させた構造体の比較は全てのプロパティの値が一致しているかを識別しています。なので以下のように1つのプロパティの値が違うインスタンス同士は一致していないとみなされ何も出力されません。
var newsns = Language(name: "Swift", version: 5)
var oldsns = Language(name: "Swift", version: 4)
if newsns == oldsns {
print("同じ言語を使用します")
}
「言語名が同じであれば一致していることにしたい」場合はEquatable
プロトコルに準拠させた構造体に==
メソッドを静的メソッドとして実装することでカスタムできます。
struct Language: Equatable {
var name: String
var version: Int
static func == (lhs: Language, rhs: Language) -> Bool {
return lhs.name == rhs.name
}
}
これで再度同じ比較を試してみると期待通り「同じ言語を使用します」が出力されました。
var newsns = Language(name: "Swift", version: 5)
var oldsns = Language(name: "Swift", version: 4)
if newsns == oldsns {
print("同じ言語を使用します") // 同じ言語を使用します
}
クラスを比較できるようにする
インスタンス(オブジェクト)の比較は構造体だけでなくクラスでも同じです。クラスのインスタンス同士をそのまま比較しようとすると同様のエラーが出てしまいます。
class Language {
var name:String = ""
var version:Int = 0
}
var ios = Language()
ios.name = "Swift"
ios.version = 5
var sns = Language()
sns.name = "php"
sns.version = 8
//
if ios == sns {
print("同じ言語を使用します")
}
エラー:binary operator '==' cannot be applied to two 'Language' operands
クラスの場合も比較対象にするプロパティを明示的に==メソッドを静的メソッドとして実装しなければいけません。
class Language: Equatable {
var name:String = ""
var version:Int = 0
static func == (lhs: Language, rhs: Language) -> Bool {
return lhs.name == rhs.name
}
}
var ios = Language()
ios.name = "Swift"
ios.version = 5
var sns = Language()
sns.name = "php"
sns.version = 8
//
if ios == sns {
print("同じ言語を使用します")
}
私がSwift UI学習に使用した参考書
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。