Wie finde ich den Index des Listenelements in Swift?


442

Ich versuche ein zu finden, item indexindem ich ein suche list. Weiß jemand, wie man das macht?

Ich sehe es gibt list.StartIndexund list.EndIndexaber ich möchte so etwas wie Pythons list.index("text").

Antworten:


822

Da Swift in mancher Hinsicht funktionaler als objektorientiert ist (und Arrays Strukturen und keine Objekte sind), verwenden Sie die Funktion "find", um das Array zu bearbeiten, das einen optionalen Wert zurückgibt. Seien Sie also darauf vorbereitet, einen Nullwert zu verarbeiten:

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

Update für Swift 2.0:

Die alte findFunktion wird mit Swift 2.0 nicht mehr unterstützt!

Mit Swift 2.0 können ArraySie den Index eines Elements mithilfe einer Funktion ermitteln, die in einer Erweiterung von CollectionType(die Arrayimplementiert) definiert ist:

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

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

Darüber hinaus wird das Finden des ersten Elements in einem Array, das ein Prädikat erfüllt, durch eine andere Erweiterung von unterstützt 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

Beachten Sie, dass diese beiden Funktionen findwie zuvor optionale Werte zurückgeben .

Update für Swift 3.0:

Beachten Sie, dass sich die Syntax von indexOf geändert hat. Für Artikel, die Ihren Anforderungen entsprechen, können EquatableSie Folgendes verwenden:

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

Eine ausführliche Dokumentation der Methode finden Sie unter https://developer.apple.com/reference/swift/array/1689674-index

Für Array-Elemente, die nicht den EquatableAnforderungen entsprechen, müssen Sie Folgendes verwenden index(where:):

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

Update für Swift 4.2:

Wird mit Swift 4.2 indexnicht mehr verwendet, sondern zur besseren Verdeutlichung in firstIndexund getrennt lastIndex. Je nachdem, ob Sie nach dem ersten oder dem letzten Index des Artikels suchen:

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

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

21
Wo haben Sie von der Suchfunktion erfahren? Ich kann anscheinend keine Dokumentation von "find" oder anderen globalen Funktionen finden
Johannes

14
Wie soll ich aus der OOP-Welt diese Art von frei schwebenden Funktionen finden?
Rudolf Adamkovič

4
Sie scheinen weitgehend undokumentiert zu sein. Siehe practicalswift.com/2014/06/14/... für eine Liste (aber beachten Sie, dass ich nicht überprüfen , ob die Liste vollständig ist oder auf dem neuesten Stand).
Sebastian Schuth

5
Johannes und @Rudolf - benutze Dash.app. Es ist eine OS X-App zum Durchsuchen der Dokumentation. Es hat eine Sprachreferenz für Swift, die eine Liste aller frei schwebenden Funktionen enthält. Einfach zu filtern und zu suchen. Kann nicht ohne leben.
Björn

4
Zu indexOfIhrer Information : Wenn Sie ein Array von Strukturen verwenden, die Sie selbst definiert haben, muss Ihre Struktur dem EquatableProtokoll entsprechen.
Matthew Quiros

202

tl; dr:

Für Klassen suchen Sie möglicherweise:

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

Vollständige Antwort:

Ich denke, es ist erwähnenswert, dass Sie mit Referenztypen ( class) möglicherweise einen Identitätsvergleich durchführen möchten. In diesem Fall müssen Sie nur den ===Identitätsoperator beim Schließen des Prädikats verwenden:


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

Beachten Sie, dass die obige Syntax die Syntax für abschließende Verschlüsse verwendet und Folgendes entspricht:

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


Swift 4 / Swift 3 - die Funktion, die früher aufgerufen wurde index

Swift 2 - die Funktion, die früher aufgerufen wurde indexOf

* Beachten Sie den relevanten und nützlichen Kommentar von paulbailey zu classimplementierten Typen Equatable, bei dem Sie überlegen müssen, ob Sie mit ===( Identitätsoperator ) oder ==( Gleichheitsoperator ) vergleichen sollten. Wenn Sie sich für eine Übereinstimmung mit entscheiden, ==können Sie einfach die von anderen vorgeschlagene Methode verwenden ( people.firstIndex(of: person1)).


6
Dies ist ein nützlicher Beitrag für diejenigen, die sich fragen, warum .indexOf (x) nicht funktioniert - diese Lösung ist unerwartet, aber im Nachhinein völlig offensichtlich.
Maury Markowitz

1
Vielen Dank dafür, aber es ist mir überhaupt nicht klar. Ich habe mir die Dokumentation angesehen und verstehe wirklich nicht, warum ich einen Prädikatabschluss benötige, wenn ich indexOf für einen Referenztyp verwende. Es scheint, dass indexOf bereits in der Lage sein sollte, Referenztypen selbst zu verarbeiten. Es sollte wissen, dass es sich um einen Referenztyp und nicht um einen Werttyp handelt.
Chris

7
Wenn Persondas EquatableProtokoll implementiert wäre, wäre dies nicht erforderlich.
Paulbailey

2
Ich erhalte: Binary operator '===' cannot be applied to operands of type '_' and 'Post', Postmeine Struktur ist ... eine Idee?
David Seek

@DavidSeek, structs(und enums) sind Werttypen, keine Referenztypen. Nur Referenztypen (z. B. class) haben eine Identitätsvergleichslogik ( ===). Schauen Sie sich die anderen Antworten an, um zu erfahren, was Sie tun sollen structs(im Grunde verwenden Sie einfach die array.index(of: myStruct), um sicherzustellen, dass der Typ myStructmit Equatable( ==) übereinstimmt ).
Nikolay Suvandzhiev

81

Sie können filterein Array mit einem Abschluss erstellen:

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

Und Sie können ein Array zählen:

filtered.count // <= returns 1

Sie können also feststellen, ob ein Array Ihr Element enthält, indem Sie diese kombinieren:

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

Wenn Sie die Position finden wollen, sehe ich keinen ausgefallenen Weg, aber Sie können es auf jeden Fall so machen:

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
    }
}

BEARBEITEN

Während wir gerade dabei sind, wollen wir für eine lustige Übung Arrayeine findMethode erweitern:

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

Jetzt können wir das tun:

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

Aus Spaß habe ich ein weiteres Beispiel hinzugefügt, in dem ich das integrierte Beispiel Arrayum eine findMethode erweitere, die das tut, was Sie wollen. Ich weiß noch nicht, ob dies eine gute Praxis ist, aber es ist ein ordentliches Experiment.
Gwcoffey

2
Ich möchte nur darauf hinweisen, dass Sie ++ idx gemäß den Dokumenten verwenden sollten: "Sofern Sie nicht das spezifische Verhalten von i ++ benötigen, wird empfohlen, in allen Fällen ++ i und --i zu verwenden, da diese den typischen Erwartungen entsprechen Verhalten beim Ändern von i und Zurückgeben des Ergebnisses. "
Logan

Guter Anruf. Als Sie dies gepostet haben, habe ich es überarbeitet, enumeratedamit es nicht mehr gilt, aber Sie haben absolut Recht.
Gwcoffey

Ja, ich erinnerte mich, dass ich es in einem der Beispiele bemerkt hatte, als ich durchging. Ich versuche mich jetzt an die Gewohnheit zu gewöhnen :)
Logan

4
Damit dies unter Swift 2 / XCode 7 funktioniert, müssen Sie es wie folgt ändern. Ersetzen Sie (includeElement: T -> Bool) durch (includeElement: Element -> Bool) und ändern Sie enumerate (self) in self.enumerate
Scooter

35

Swift 5

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

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

Beispiel 1

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

Beispiel2

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

25

Funktioniert zwar indexOf()einwandfrei, gibt jedoch nur einen Index zurück.

Ich suchte nach einer eleganten Möglichkeit, eine Reihe von Indizes für Elemente zu erhalten, die bestimmte Bedingungen erfüllen.

So geht's:

Swift 3:

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

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

print(indexes)

Swift 2:

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

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

print(indexes)

12

Für benutzerdefinierte Klassen müssen Sie das Equatable-Protokoll implementieren.

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

Update für Swift 2:

sequence.contains (element) : Gibt true zurück, wenn eine bestimmte Sequenz (z. B. ein Array) das angegebene Element enthält.

Swift 1:

Wenn Sie nur überprüfen möchten, ob ein Element in einem Array enthalten ist, dh nur einen booleschen Indikator erhalten, verwenden Sie contains(sequence, element)anstelle von find(array, element):

enthält (Sequenz, Element) : Gibt true zurück, wenn eine bestimmte Sequenz (z. B. ein Array) das angegebene Element enthält.

Siehe Beispiel unten:

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.   
}

7

in Swift 4.2

.index (wo :) wurde in .firstIndex (wo :) geändert

array.firstIndex(where: {$0 == "person1"})

6

Swift 4. Wenn Ihr Array Elemente vom Typ [String: AnyObject] enthält. Um den Index des Elements zu finden, verwenden Sie den folgenden Code

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)

Oder Wenn Sie einen Index auf der Grundlage eines Schlüssels aus dem Wörterbuch finden möchten. Hier enthält das Array Objekte der Modellklasse und ich stimme mit der ID-Eigenschaft überein.

   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"]

Swift 3

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

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

3
Sie mutieren ein let array? Die Verwendung von selfist ebenfalls fraglich.
Chéyo

4

Wenn Sie in Swift 4 Ihr DataModel-Array durchlaufen, stellen Sie sicher, dass Ihr Datenmodell dem Equatable Protocol entspricht, implementieren Sie die Methode lhs = rhs, und nur dann können Sie beispielsweise ".index (of") verwenden

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

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

Und dann,

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

4

ArrayEnthält in Swift 2 (mit Xcode 7) eine indexOfvom CollectionTypeProtokoll bereitgestellte Methode . (Tatsächlich zwei indexOfMethoden - eine, die Gleichheit verwendet, um einem Argument zu entsprechen, und eine andere , die einen Abschluss verwendet.)

Vor Swift 2 gab es für generische Typen wie Sammlungen keine Möglichkeit, Methoden für die daraus abgeleiteten konkreten Typen (wie Arrays) bereitzustellen. In Swift 1.x ist "index of" eine globale Funktion ... und es wurde auch umbenannt. In Swift 1.x wird diese globale Funktion aufgerufen find.

Es ist auch möglich (aber nicht erforderlich), die indexOfObjectMethode von NSArray... oder eine andere, komplexere Suchmethode von Foundation zu verwenden, die keine Entsprechungen in der Swift-Standardbibliothek enthält. Nur import Foundation(oder ein anderes Modul , dass transitively importiert Foundation), werfen Sie Ihre Arrayzu NSArray, und Sie können auf die vielen Suchmethoden verwenden NSArray.


4

Jede dieser Lösungen funktioniert für mich

Dies ist die Lösung, die ich für Swift 4 habe:

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

Wenn Sie noch in Swift 1.x arbeiten

dann versuche es,

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

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

1

Für SWIFT 3 können Sie eine einfache Funktion verwenden

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

Dies gibt die Nummer Position, so dass Sie wie verwenden können

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

Ich hoffe, nützlich zu sein


1

SWIFT 4

Angenommen, Sie möchten eine Nummer aus dem Array cardButtons in cardNumber speichern. Dies können Sie folgendermaßen tun:

let cardNumber = cardButtons.index(of: sender)

Absender ist der Name Ihrer Schaltfläche


0

Swift 4

Für Referenztypen:

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

Verwenden Sie in Swift 4/5 "firstIndex", um den Index zu finden.

let index = array.firstIndex{$0 == value}

0

Falls jemand dieses Problem hat

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

Aber mach das

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

dann

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

0

Zum (>= swift 4.0)

Es ist ziemlich einfach. Betrachten Sie das folgende ArrayObjekt.

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

Um den Index des Elements zu erhalten rose, müssen Sie lediglich Folgendes tun:

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

Hinweis:

  • Array.index(of:)gibt ein zurück Optional<Int>.

  • nil impliziert, dass das Element nicht im Array vorhanden ist.

  • Möglicherweise möchten Sie den zurückgegebenen Wert zwangsweise auspacken oder ein verwenden if-let, um das optionale zu umgehen .


0

Verwenden Sie einfach die firstIndex-Methode.

array.firstIndex(where: { $0 == searchedItem })
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.