配列内のオブジェクトを見つけますか?


144

Swiftには_.findWhereのようなものがありますか Underscore.jsのますか?

タイプの構造体のT配列があり、nameプロパティがに等しい構造体オブジェクトが配列に含まれているかどうかを確認したいと思いますFoo

使用しようfind()としましたfilter()が、Stringまたはなどのプリミティブ型でのみ機能しIntます。Equitableプロトコルに準拠していないなどのエラーをスローします。


これはあなたが探しているものかもしれません:Array内のプロパティを持つオブジェクトを検索します。
マーティンR

NSDictionaryのに変換を検索しない理由
ロングボウ

3
Swift 2.0でfindが利用できなくなったと思います。1.2コードをSwift 2.0に変換していたところ、代わりにIndexOfを使用すると言われていました。
Swift Soda

回答:


91

FWIW、カスタム関数または拡張機能を使用したくない場合は、次のことができます。

let array = [ .... ]
if let found = find(array.map({ $0.name }), "Foo") {
    let obj = array[found]
}

これはname最初に配列を生成し、次にfindからします。

巨大な配列がある場合は、次のようにすることができます。

if let found = find(lazy(array).map({ $0.name }), "Foo") {
    let obj = array[found]
}

または多分:

if let found = find(lazy(array).map({ $0.name == "Foo" }), true) {
    let obj = array[found]
}

これはさらに良いです。全体的にシンプルに見え、カスタム関数を作成する必要がないため、これを回答としてマークします。
Sahat Yalkabov、2015

27
Swift 2.0以降では、次を使用できます。array.indexOf({$ 0.name == "Foo"})
tf.alves

73
Swift 3.0では、オブジェクトが必要な場合、array.first(where:{$ 0.name == "Foo"})を使用できます
Brett

$ 0.nameに文字列「foo」が含まれていることを確認するにはどうすればよいですか?答えは完全一致についてです。文字列が必要です。誰でもその構文を提供できますか
Azik Abdullah

290

SWIFT 5

要素が存在するかどうかを確認します

if array.contains(where: {$0.name == "foo"}) {
   // it exists, do something
} else {
   //item could not be found
}

要素を取得する

if let foo = array.first(where: {$0.name == "foo"}) {
   // do something with foo
} else {
   // item could not be found
}

要素とそのオフセットを取得する

if let foo = array.enumerated().first(where: {$0.element.name == "foo"}) {
   // do something with foo.offset and foo.element
} else {
   // item could not be found
}

オフセットを取得する

if let fooOffset = array.firstIndex(where: {$0.name == "foo"}) {
    // do something with fooOffset
} else {
    // item could not be found
}

6
素敵なスウィフトスタイルの答え!
ゾルタン

4
おかげで私の節約者これは私のコードをたくさんきれいにしました
AD Progress

複数の条件をチェックする方法は、アレイ$0.name == "foo"が1つの操作を$0.name == "boo" 実行し、別の操作を 実行するかどうかを確認する必要があると言い ます
Midhun Narayan

これは、2020年には、より受け入れ答えよりも私を助けた
Psiloc

$ 0.nameに文字列「foo」が含まれていることを確認するにはどうすればよいですか?誰でもその構文を提供できますか
Azik Abdullah

131

あなたは使用することができますindex上で利用できる方法をArray(述語とここでは、Appleのドキュメントを参照してください)。

func index(where predicate: (Element) throws -> Bool) rethrows -> Int?

具体的な例としては、次のようになります。

Swift 5.0

if let i = array.firstIndex(where: { $0.name == "Foo" }) {
    return array[i]
}

Swift 3.0

if let i = array.index(where: { $0.name == Foo }) {
    return array[i]
}

Swift 2.0

if let i = array.indexOf({ $0.name == Foo }) {
    return array[i]
}

3
はい、これはSwift 2.0でのみ機能します。申し訳ありませんがそれを述べるべきでした。
user3799504 2015

@ user3799504 $ 0の意味?
Pramod Tapaniya

$ 0は、クロージャーの最初の引数の省略形です。この場合、それはself.generator.elementまたは配列の各要素を参照します。見てください:developer.apple.com/library/ios/documentation/Swift/Conceptual/...
user3799504

1
Swift 3はどうですか?
adnako

38

スウィフト3

オブジェクトの使用が必要な場合:

array.first{$0.name == "Foo"}

(「Foo」という名前のオブジェクトが複数ある場合first、指定されていない順序で最初のオブジェクトを返します)


これありがとう。これはそこまでのはずです!
NerdyTherapist 2017年

3
これはいいです、ありがとう!また、このように書くことができます:array.first {$0.name == "Foo"}
ローランドT.

2
Swift3ではarray.first(where: {$0.name == "Foo"})
ダニエル

ダニエルのメモによると、これはSwift 3の正しい最良の答えです。この目的でマップやフィルターを使用しないでください。コレクション全体を繰り返し処理するため、非常に無駄が多くなる可能性があります。
Womble

20

「配列内のプロパティを使用してオブジェクトを検索」に示すように、配列をフィルターして最初の要素を選択するだけです。

または、カスタム拡張を定義します

extension Array {

    // Returns the first element satisfying the predicate, or `nil`
    // if there is no matching element.
    func findFirstMatching<L : BooleanType>(predicate: T -> L) -> T? {
        for item in self {
            if predicate(item) {
                return item // found
            }
        }
        return nil // not found
    }
}

使用例:

struct T {
    var name : String
}

let array = [T(name: "bar"), T(name: "baz"), T(name: "foo")]

if let item = array.findFirstMatching( { $0.name == "foo" } ) {
    // item is the first matching array element
} else {
    // not found
}

スウィフト3既存使用することができますfirst(where:)(のような方法をコメントに言及しました):

if let item = array.first(where: { $0.name == "foo" }) {
    // item is the first matching array element
} else {
    // not found
}

効率の面で、これはどのように比較しarray.lazy.filter( predicate ).firstますか?小さな配列の.lazyはどのくらい効率的ですか?
Pat Niemeyer 2016年

@PatNiemeyer:わかりません。パフォーマンスを測定して比較する必要があります。
マーティンR

@PatNiemeyer上記のソリューションは、違いがおそらく大きくない場合でも、確かにより効率的です。1.の複雑さfilterは常にでO(n)あるのに対して、findFirstMatchingそれは最悪のシナリオでのみです(探している要素が配列の最後かまったくない場合)。2. filterfindFirstMatching要求された要素を返すだけで、フィルタリングされた要素の完全に新しい配列を作成します。
0101

Swift 3では、この拡張メソッドに対して、非プロトコル、非クラスタイプ「Bool」からの継承エラーおよび宣言されていないタイプ「T」の使用が発生します。
Isuru

@Isuru:その答えはかなり古く、古いSwiftバージョンを参照していました。Swift 3では、そのためにカスタム拡張メソッドはもう必要ありません。それに応じて答えを更新しました。
マーティンR

20

Swift 3.0

if let index = array.index(where: { $0.name == "Foo" }) {
    return array[index]
}

Swift 2.1

オブジェクトプロパティでのフィルタリングがSwift 2.1でサポートされるようになりました。構造体またはクラスの値に基づいて配列をフィルタリングできます。ここに例を示します。

for myObj in myObjList where myObj.name == "foo" {
 //object with name is foo
}

または

for myObj in myObjList where myObj.Id > 10 {
 //objects with Id is greater than 10
}

9

スウィフト4

フィルター機能を使用してこれを達成する別の方法は、

if let object = elements.filter({ $0.title == "title" }).first {
    print("found")
} else {
    print("not found")
}

8

スウィフト3

あなたはSwift 3でindex(where :)を使うことができます

func index(where predicate: @noescape Element throws -> Bool) rethrows -> Int?

if let i = theArray.index(where: {$0.name == "Foo"}) {
    return theArray[i]
}

Swift 3に、条件を満たす配列項目のサブリストのインデックスを見つける方法はあります$0.name == "Foo"か?
Ahmed Khedr 16

3

スウィフト3

if yourArray.contains(item) {
   //item found, do what you want
}
else{
   //item not found 
   yourArray.append(item)
}

2

Swift 2以降

あなたは組み合わせることができますindexOfし、map単一の行に「検索要素」関数を記述すること。

let array = [T(name: "foo"), T(name: "Foo"), T(name: "FOO")]
let foundValue = array.indexOf { $0.name == "Foo" }.map { array[$0] }
print(foundValue) // Prints "T(name: "Foo")"

filter+ を使用するとfirst見た目はきれいにfilterなりますが、配列内のすべての要素が評価されます。indexOf+ map複雑に見えますが、配列内の最初の一致が見つかると評価は停止します。どちらのアプローチにも長所と短所があります。


1

使用contains

var yourItem:YourType!
if contains(yourArray, item){
    yourItem = item
}

または、コメントでマーティンが指摘したことをfilter試して、もう一度試してみてください:配列内のプロパティを使用してオブジェクトを検索する


それはブール値のみを返しますか?オブジェクトが配列にあるかどうかを確認するだけでなく、オブジェクトも取得する必要があります。
Sahat Yalkabov、2015

これitemは、配列内のitemと同じタイプであると想定しています。ただし、私が持っているのはからのタイトルだけview.annotation.titleです。このタイトルで配列内の項目を比較する必要があります。
Sahat Yalkabov、2015

のようなものif contains(yourArray, view.annotation.title) { // code goes here }
Sahat Yalkabov、2015

マーティンはコメントで別の方法を示しました。彼が提供したリンクを確認してください。
クリスチャン

1

array.index(of:Any)にアクセスする別の方法は、オブジェクトを宣言することです

import Foundation
class Model: NSObject {  }


1

スウィフト3:

Swiftsの組み込み機能を使用して、配列内のカスタムオブジェクトを検索できます。

まず、カスタムオブジェクトがEquatableプロトコルに準拠していることを確認する必要があります

class Person : Equatable { //<--- Add Equatable protocol
    let name: String
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    //Add Equatable functionality:
    static func == (lhs: Person, rhs: Person) -> Bool {
        return (lhs.name == rhs.name)
    }
}

Equatable機能をオブジェクトに追加すると、Swiftは配列で使用できる追加のプロパティを表示します。

//create new array and populate with objects:
let p1 = Person(name: "Paul", age: 20)
let p2 = Person(name: "Mike", age: 22)
let p3 = Person(name: "Jane", age: 33)
var people = [Person]([p1,p2,p3])

//find index by object:
let index = people.index(of: p2)! //finds Index of Mike

//remove item by index:
people.remove(at: index) //removes Mike from array


0

たとえば、数値の配列がある場合:

let numbers = [2, 4, 6, 8, 9, 10]

次のような最初の奇数を見つけることができます:

let firstOdd = numbers.index { $0 % 2 == 1 }

最初の奇数(9)はインデックス4にあるので、オプションの整数として4が返されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.