Swiftでリストアイテムのインデックスを見つける方法は?


442

を検索しitem indexてを見つけようとしていますlist。誰かがそれを行う方法を知っていますか?

私はそこで見るlist.StartIndexと、list.EndIndex私はPythonのような何かをしたいですlist.index("text")

回答:


822

swiftはいくつかの点でオブジェクト指向(および配列はオブジェクトではなく構造体)よりも機能的であるため、関数「find」を使用して配列を操作します。これはオプションの値を返すため、nil値を処理する準備をしてください。

let arr:Array = ["a","b","c"]
find(arr, "c")!              // 2
find(arr, "d")               // nil

Swift 2.0の更新:

古いfind関数はSwift 2.0ではサポートされなくなりました!

Swift 2.0では、(の実装)のArray拡張で定義された関数を使用して、要素のインデックスを検索する機能が得られます。CollectionTypeArray

let arr = ["a","b","c"]

let indexOfA = arr.indexOf("a") // 0
let indexOfB = arr.indexOf("b") // 1
let indexOfD = arr.indexOf("d") // nil

さらに、述語を満たす配列の最初の要素の検索は、の別の拡張によってサポートされていCollectionTypeます。

let arr2 = [1,2,3,4,5,6,7,8,9,10]
let indexOfFirstGreaterThanFive = arr2.indexOf({$0 > 5}) // 5
let indexOfFirstGreaterThanOneHundred = arr2.indexOf({$0 > 100}) // nil

これら2つの関数findは、以前と同様にオプションの値を返すことに注意してください。

Swift 3.0の更新:

indexOfの構文が変更されていることに注意してください。Equatableあなたに適合するアイテムのために使うことができます:

let indexOfA = arr.index(of: "a")

メソッドの詳細なドキュメントは、https://developer.apple.com/reference/swift/array/1689674-indexにあります。

準拠していない配列項目のEquatable場合は、以下を使用する必要がありますindex(where:)

let index = cells.index(where: { (item) -> Bool in
  item.foo == 42 // test if this is the item you're looking for
})

Swift 4.2の更新:

Swift 4.2では、indexは使用されなくなりましたが、明確化のためにに分離されfirstIndexlastIndexいます。したがって、アイテムの最初または最後のインデックスを探しているかどうかに応じて、

let arr = ["a","b","c","a"]

let indexOfA = arr.firstIndex(of: "a") // 0
let indexOfB = arr.lastIndex(of: "a") // 3

22
検索機能についてどこで学びましたか?「検索」またはその他のグローバル関数のドキュメントが見つからないようです
Johannes

14
OOPの世界から来たのですが、この種のフリーフローティング関数をどのようにして見つけるべきですか?
RudolfAdamkovič2014

4
それらはほとんど文書化されていないようです。リストについては、practicalswift.com / 2014/06/14 /…を参照してください(ただし、リストが完全であるか、最新かどうかは確認していません)。
Sebastian Schuth 2014

5
Johannesと@Rudolf-Dash.appを使用します。ドキュメントを閲覧するためのOS Xアプリです。すべてのフリーフローティング関数のリストを含むSwiftの言語リファレンスがあります。フィルタリングと検索が簡単。それなしでは生きられない。
ビョルン2015年

4
indexOf参考:自分で定義した構造体の配列を使用している場合、構造体はEquatableプロトコルに準拠している必要があります。
Matthew Quiros、2015

202

tl; dr:

クラスの場合、以下を探している可能性があります。

let index = someArray.firstIndex{$0 === someObject}

完全な答え:

参照型(class)でID比較を実行する必要がある場合があることに言及する価値があると思います。この場合===、述語クロージャーでID演算子を使用する必要があるだけです。


Swift 5、Swift 4.2:

let person1 = Person(name: "John")
let person2 = Person(name: "Sue")
let person3 = Person(name: "Maria")
let person4 = Person(name: "Loner")

let people = [person1, person2, person3]

let indexOfPerson1 = people.firstIndex{$0 === person1} // 0
let indexOfPerson2 = people.firstIndex{$0 === person2} // 1
let indexOfPerson3 = people.firstIndex{$0 === person3} // 2
let indexOfPerson4 = people.firstIndex{$0 === person4} // nil

上記の構文は末尾クロージャ構文を使用しており、以下と同等であることに注意してください。

let indexOfPerson1 = people.firstIndex(where: {$0 === person1})


Swift 4 / Swift 3-以前呼び出されていた関数 index

Swift 2-以前は呼び出されていた関数 indexOf

*該当すると便利に注意してくださいコメントによってpaulbaileyに関するclass実装タイプのEquatableあなたが使用して比較する必要があるかどうかを検討する必要がある、===恒等演算子)または==等号演算子を)。を使用して照合する場合==は、他のユーザーが提案した方法を使用できます(people.firstIndex(of: person1))。


6
これは、なぜ.indexOf(x)が機能しないのか疑問に思う方に役立つ投稿です。このソリューションは予想外ですが、振り返ってみると完全に明白です。
Maury Markowitz、2016

1
どうもありがとうございましたが、私にはまったくわかりません。ドキュメントを見て、参照型でindexOfを使用するときになぜ述語クロージャが必要なのか本当にわかりません。indexOfは、それ自体で参照型をすでに処理できるはずです。それは参照型であり、値型ではないことを知っている必要があります。
Chris

7
プロトコルをPerson実装する場合Equatable、これは必要ありません。
ポールベイリー

2
私は受け取っています:Binary operator '===' cannot be applied to operands of type '_' and 'Post'Post私の構造体...何か考えはありますか?
デビッドシーク2016

@DavidSeek structs(およびenums)は参照型ではなく値型です。参照タイプ(などclass)のみがID比較ロジック(===)を持っています。何をどうするかについては、他の回答を確認してくださいstructs(基本的に、単にを使用しarray.index(of: myStruct)、タイプが()にmyStruct準拠していることを確認します)。Equatable==
Nikolay Suvandzhiev

81

あなたはfilterクロージャーで配列することができます:

var myList = [1, 2, 3, 4]
var filtered = myList.filter { $0 == 3 }  // <= returns [3]

そして、あなたは配列を数えることができます:

filtered.count // <= returns 1

したがって、これらを組み合わせることで、配列に要素が含まれているかどうかを判断できます。

myList.filter { $0 == 3 }.count > 0  // <= returns true if the array includes 3

あなたがポジションを見つけたいのであれば、私は空想的な方法を見ていませんが、あなたは確かにこのようにそれを行うことができます:

var found: Int?  // <= will hold the index if it was found, or else will be nil
for i in (0..x.count) {
    if x[i] == 3 {
        found = i
    }
}

編集

その間、楽しいエクササイズのArrayために、findメソッドを持つように拡張しましょう:

extension Array {
    func find(includedElement: T -> Bool) -> Int? {
        for (idx, element) in enumerate(self) {
            if includedElement(element) {
                return idx
            }
        }
        return nil
    }
}

これでこれを行うことができます:

myList.find { $0 == 3 }
// returns the index position of 3 or nil if not found

ファンシーのために、私はあなたが望むことをArrayするfindメソッドを持つようにビルトインを拡張する別の例を追加しました。これが良い習慣かどうかはまだわかりませんが、きちんとした実験です。
gwcoffey 2014年

2
指摘したいのは、ドキュメントに従って++ idxを使用する必要があることです。「i ++の特定の動作が必要でない限り、すべてのケースで++ iと--iを使用することをお勧めします。 iを変更して結果を返す動作。」
ローガン2014年

よかった。あなたがこれを投稿していたとき、私はそれを使用するenumerateように改訂していたので、もう適用されませんが、あなたは完全に正しいです。
gwcoffey 2014年

ええ、私はそれを経験しているときの例の1つでそれに気付いたことを覚えていました。今自分を習慣にしようとしている:)
Logan

4
これをSwift 2 / XCode 7で動作させるには、次のように変更する必要があります。(includedElement:T-> Bool)を(includedElement:Element-> Bool)に置き換え、enumerate(self)をself.enumerateに変更します
Scooter

35

スウィフト5

func firstIndex(of element: Element) -> Int?

var alphabets = ["A", "B", "E", "D"]

例1

let index = alphabets.firstIndex(where: {$0 == "A"})

例2

if let i = alphabets.firstIndex(of: "E") {
    alphabets[i] = "C" // i is the index
}
print(alphabets)
// Prints "["A", "B", "C", "D"]"

25

indexOf()完璧に機能する一方で、それは唯一のインデックスを返します。

ある条件を満たす要素のインデックスの配列を取得するエレガントな方法を探していました。

以下にその方法を示します。

スウィフト3:

let array = ["apple", "dog", "log"]

let indexes = array.enumerated().filter {
    $0.element.contains("og")
    }.map{$0.offset}

print(indexes)

スウィフト2:

let array = ["apple", "dog", "log"]

let indexes = array.enumerate().filter {
    $0.element.containsString("og")
    }.map{$0.index}

print(indexes)

12

カスタムクラスの場合、Equatableプロトコルを実装する必要があります。

import Foundation

func ==(l: MyClass, r: MyClass) -> Bool {
  return l.id == r.id
}

class MyClass: Equtable {
    init(id: String) {
        self.msgID = id
    }

    let msgID: String
}

let item = MyClass(3)
let itemList = [MyClass(1), MyClass(2), item]
let idx = itemList.indexOf(item)

printl(idx)

9

Swift 2の更新:

sequence.contains(element):指定されたシーケンス(配列など)に指定されたエレメントが含まれている場合にtrueを返します。

スウィフト1:

要素が配列内に含まれているかどうかを確認するだけの場合、つまりブールインジケーターを取得するだけの場合contains(sequence, element)は、find(array, element)次の代わりに使用します。

contains(sequence、element):指定されたシーケンス(配列など)に指定された要素が含まれている場合にtrueを返します。

以下の例をご覧ください。

var languages = ["Swift", "Objective-C"]
contains(languages, "Swift") == true
contains(languages, "Java") == false
contains([29, 85, 42, 96, 75], 42) == true
if (contains(languages, "Swift")) {
  // Use contains in these cases, instead of find.   
}


6

Swift 4.配列に[String:AnyObject]タイプの要素が含まれている場合。要素のインデックスを見つけるには、以下のコードを使用します

var array = [[String: AnyObject]]()// Save your data in array
let objectAtZero = array[0] // get first object
let index = (self.array as NSArray).index(of: objectAtZero)

または、辞書のキーに基づいてインデックスを検索する場合。ここで、配列にはモデルクラスのオブジェクトが含まれており、idプロパティと一致しています。

   let userId = 20
    if let index = array.index(where: { (dict) -> Bool in
           return dict.id == userId // Will found index of matched id
    }) {
    print("Index found")
    }
OR
      let storeId = Int(surveyCurrent.store_id) // Accessing model key value
      indexArrUpTo = self.arrEarnUpTo.index { Int($0.store_id) == storeId }! // Array contains models and finding specific one

4

Swift 2.1

var array = ["0","1","2","3"]

if let index = array.indexOf("1") {
   array.removeAtIndex(index)
}

print(array) // ["0","2","3"]

スウィフト3

var array = ["0","1","2","3"]

if let index = array.index(of: "1") {
    array.remove(at: index)
}
array.remove(at: 1)

3
あなたは変異していlet arrayますか?の使用にselfも疑問があります。
Chéyo

4

スウィフト4あなたがたDataModelの列を横断している場合は、この方法をRHS = LHSを実装し、Equatable議定書に必ずデータモデルの適合を行い、その後にのみ、あなたは「の(.INDEX」を使用することができます。たとえば、

class Photo : Equatable{
    var imageURL: URL?
    init(imageURL: URL){
        self.imageURL = imageURL
    }

    static func == (lhs: Photo, rhs: Photo) -> Bool{
        return lhs.imageURL == rhs.imageURL
    }
}

その後、

let index = self.photos.index(of: aPhoto)

4

Swift 2(Xcode 7を使用)にArrayindexOfCollectionTypeプロトコルによって提供されるメソッドが含まれています。(実際には、2つのindexOf方法-引数を一致させるために等式を使用する方法とクロージャを使用します。)

Swift 2以前は、コレクションなどのジェネリック型がそれらから派生した具象型(配列など)のメソッドを提供する方法はありませんでした。したがって、Swift 1.xでは「index of」はグローバル関数です...そして、名前も変更されたため、Swift 1.xではそのグローバル関数が呼び出されfindます。

... のindexOfObjectメソッドNSArrayや、Swift標準ライブラリに同等のものを持たないFoundationのその他のより洗練された検索メソッドを使用することも可能です(ただし必須ではありません)。ただimport Foundation(またはFoundationを推移的にインポートする別のモジュール)、をにキャストするArrayNSArray、で多くの検索メソッドを使用できますNSArray


4

この解決策はどれも私にとってはうまくいきます

これは私がSwift 4のために持っている解決策です:

let monday = Day(name: "M")
let tuesday = Day(name: "T")
let friday = Day(name: "F")

let days = [monday, tuesday, friday]

let index = days.index(where: { 
            //important to test with === to be sure it's the same object reference
            $0 === tuesday
        })


2

まだSwift 1.xで作業している場合

その後、

let testArray = ["A","B","C"]

let indexOfA = find(testArray, "A") 
let indexOfB = find(testArray, "B")
let indexOfC = find(testArray, "C")

1

SWIFT 3の場合、単純な関数を使用できます

func find(objecToFind: String?) -> Int? {
   for i in 0...arrayName.count {
      if arrayName[i] == objectToFind {
         return i
      }
   }
return nil
}

これは番号の位置を与えるので、次のように使用できます

arrayName.remove(at: (find(objecToFind))!)

役立つことを願っています


1

SWIFT 4

cardButtonsという配列の数値をcardNumberに格納するとします。次のようにできます。

let cardNumber = cardButtons.index(of: sender)

送信者はボタンの名前です


0

スウィフト4

参照タイプの場合:

extension Array where Array.Element: AnyObject {

    func index(ofElement element: Element) -> Int? {
        for (currentIndex, currentElement) in self.enumerated() {
            if currentElement === element {
                return currentIndex
            }
        }
        return nil
    }
}


0

誰かがこの問題を抱えている場合

Cannot invoke initializer for type 'Int' with an argument list of type '(Array<Element>.Index?)'

これを行う

extension Int {
    var toInt: Int {
        return self
    }
}

その後

guard let finalIndex = index?.toInt else {
    return false
}

0

ために (>= swift 4.0)

かなりシンプルです。次のArrayオブジェクトを考えます。

var names: [String] = ["jack", "rose", "jill"]

要素のインデックスを取得するために必要なことは、次のroseとおりです。

names.index(of: "rose") // returns 1

注意:

  • Array.index(of:)を返しますOptional<Int>

  • nil 要素が配列に存在しないことを意味します。

  • 戻り値を強制的にアンラップするかif-let、オプションを回避するためにを使用することができます。


0

firstIndexメソッドを使用するだけです。

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