Come trovare l'indice della voce di elenco in Swift?


443

Sto cercando di trovare un item indexcercando a list. Qualcuno sa come farlo?

Vedo che c'è list.StartIndexe list.EndIndexvoglio qualcosa come Python list.index("text").

Risposte:


824

Poiché swift è per alcuni aspetti più funzionale di orientato agli oggetti (e le matrici sono strutture, non oggetti), utilizzare la funzione "trova" per operare sull'array, che restituisce un valore opzionale, quindi preparatevi a gestire un valore nullo:

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

Aggiornamento per Swift 2.0:

La vecchia findfunzione non è più supportata con Swift 2.0!

Con Swift 2.0, Arrayacquisisce la capacità di trovare l'indice di un elemento usando una funzione definita in un'estensione di CollectionType(che Arrayimplementa):

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

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

Inoltre, trovare il primo elemento in un array che soddisfa un predicato è supportato da un'altra estensione di 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

Si noti che queste due funzioni restituiscono valori opzionali, come in findprecedenza.

Aggiornamento per Swift 3.0:

Si noti che la sintassi di indexOf è cambiata. Per gli articoli conformi a Equatablete puoi usare:

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

Una documentazione dettagliata del metodo è disponibile all'indirizzo https://developer.apple.com/reference/swift/array/1689674-index

Per gli elementi dell'array che non sono conformi Equatableè necessario utilizzare index(where:):

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

Aggiornamento per Swift 4.2:

Con Swift 4.2, indexnon viene più utilizzato ma è separato firstIndexe lastIndexper un migliore chiarimento. Quindi, a seconda che tu stia cercando il primo o l'ultimo indice dell'articolo:

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

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

22
Dove hai appreso sulla funzione di ricerca? Non riesco a trovare alcuna documentazione su "trova" o altre funzioni globali
Johannes,

14
Proveniente dal mondo OOP, come posso trovare questo tipo di funzioni fluttuanti libere?
Rudolf Adamkovič,

4
Sembrano essere ampiamente privi di documenti. Consulta practiceswift.com/2014/06/14/… per un elenco (ma tieni presente che non ho verificato se l'elenco è completo o aggiornato).
Sebastian Schuth,

5
Johannes e @Rudolf - usa Dash.app. È un'app OS X per la navigazione della documentazione. Ha un riferimento linguistico per Swift che ha un elenco di tutte le funzioni mobili libere. Facile da filtrare e cercare. Non posso vivere senza di essa.
Bjorn,

4
Cordiali saluti: Se si utilizza indexOfsu una serie di strutture definite dall'utente, la struttura deve essere conforme al Equatableprotocollo.
Matthew Quiros,

202

tl; dr:

Per le classi, potresti essere alla ricerca di:

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

Risposta completa:

Penso che valga la pena ricordare che con i tipi di riferimento ( class) potresti voler eseguire un confronto di identità , nel qual caso devi solo usare l' ===operatore di identità nella chiusura del predicato:


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

Si noti che la sintassi precedente utilizza la sintassi delle chiusure finali ed equivale a:

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


Swift 4 / Swift 3 - la funzione utilizzata per essere chiamata index

Swift 2 - la funzione utilizzata per essere chiamata indexOf

* Nota il commento utile e pertinente di paulbailey sui classtipi che implementano Equatable, in cui devi considerare se devi confrontare usando ===( operatore identità ) o ==( operatore uguaglianza ). Se decidi di abbinare usando ==, puoi semplicemente usare il metodo suggerito da altri ( people.firstIndex(of: person1)).


6
Questo è un post utile per coloro che si chiedono perché .indexOf (x) non funziona: questa soluzione è inaspettata ma perfettamente ovvia in retrospettiva.
Maury Markowitz,

1
Grazie mille per questo, ma per me non è affatto ovvio. Ho guardato la documentazione e non capisco davvero perché dovrei aver bisogno di una chiusura predicata quando uso indexOf su un tipo di riferimento? Sembra che IndexOf dovrebbe già essere in grado di gestire i tipi di riferimento da solo. Dovrebbe sapere che è un tipo di riferimento e non un tipo di valore.
Chris

7
Se Personimplementato il Equatableprotocollo, questo non sarebbe necessario.
paulbailey,

2
Ricevo: Binary operator '===' cannot be applied to operands of type '_' and 'Post', Postè il mio struct ... qualche idea?
David Seek,

@DavidSeek, structs(e enums) sono tipi di valore, non tipi di riferimento. Solo i tipi di riferimento (ad es. class) Hanno una logica di confronto delle identità ( ===). Controlla le altre risposte su cosa fare structs(in pratica usi semplicemente il array.index(of: myStruct), assicurandoti che sia myStructconforme a Equatable( ==)).
Nikolay Suvandzhiev,

81

È possibile filterun array con una chiusura:

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

E puoi contare un array:

filtered.count // <= returns 1

Quindi puoi determinare se un array include il tuo elemento combinando questi:

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

Se vuoi trovare la posizione, non vedo un modo elegante, ma puoi certamente farlo in questo modo:

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

MODIFICARE

Mentre ci siamo, per un esercizio divertente estendiamo Arrayad avere un findmetodo:

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

Ora possiamo fare questo:

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

Per motivi di divertimento ho aggiunto un altro esempio in cui estendo l'integrato Arrayper avere un findmetodo che fa quello che vuoi. Non so ancora se questa è una buona pratica, ma è un esperimento accurato.
gwcoffey,

2
Voglio solo sottolineare che dovresti usare ++ idx come da documenti: "A meno che tu non abbia bisogno del comportamento specifico di i ++, si consiglia di usare ++ i e --i in tutti i casi, perché hanno il tipico previsto comportamento di modifica di i e restituzione del risultato. "
Logan,

Ottima scelta. Mentre lo stavi postando, lo stavo rivedendo per usarlo, enumeratequindi non si applica più, ma hai assolutamente ragione.
gwcoffey,

Sì, mi sono ricordato di averlo notato in uno degli esempi che stavo attraversando. Sto cercando di prendere l'abitudine adesso :)
Logan,

4
Affinché funzioni sotto Swift 2 / XCode 7, è necessario modificarlo come segue. Sostituisci (inclusoElemento: T -> Bool) con (inclusoElemento: Elemento -> Bool) e cambia enumerare (self) in self.enumerate
Scooter

35

Swift 5

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

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

Esempio 1

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

Esempio 2

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

25

Mentre indexOf()funziona perfettamente, restituisce solo un indice.

Stavo cercando un modo elegante per ottenere una serie di indici per elementi che soddisfano alcune condizioni.

Ecco come si può fare:

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

Per la classe personalizzata, è necessario implementare il protocollo 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

Aggiornamento per Swift 2:

sequence.contains (element) : restituisce true se una determinata sequenza (come una matrice) contiene l'elemento specificato.

Swift 1:

Se stai solo cercando di verificare se un elemento è contenuto in un array, ovvero ottieni un indicatore booleano, usa contains(sequence, element)invece di find(array, element):

contiene (sequenza, elemento) : restituisce vero se una determinata sequenza (come una matrice) contiene l'elemento specificato.

Vedi l'esempio seguente:

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 (dove :) è stato modificato in .firstIndex (dove :)

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

6

Swift 4. Se l'array contiene elementi di tipo [String: AnyObject]. Quindi per trovare l'indice dell'elemento usa il codice qui sotto

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)

Oppure se si desidera trovare l'indice sulla base della chiave dal dizionario. Qui la matrice contiene oggetti della classe Model e sto abbinando la proprietà 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"]

Swift 3

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

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

3
stai mutando un let array? L'uso di selfè anche discutibile.
Chéyo,

4

In Swift 4 , se stai attraversando l'array DataModel, assicurati che il tuo modello di dati sia conforme al Protocollo equabile, implementa il metodo lhs = rhs e solo allora puoi usare ".index (of". Ad esempio

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

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

E poi,

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

4

In Swift 2 (con Xcode 7), Arrayinclude un indexOfmetodo fornito dal CollectionTypeprotocollo. (In realtà, due indexOfmetodi: uno che utilizza l'uguaglianza per abbinare un argomento e un altro che utilizza una chiusura.)

Prima di Swift 2, non c'era modo per i tipi generici come le raccolte di fornire metodi per i tipi concreti da loro derivati ​​(come gli array). Quindi, in Swift 1.x, "index of" è una funzione globale ... E anche questa è stata rinominata, quindi in Swift 1.x, quella funzione globale è chiamatafind .

È anche possibile (ma non necessario) utilizzare il indexOfObjectmetodo da NSArray... o da qualsiasi altro metodo di ricerca più sofisticato di Foundation che non ha equivalenti nella libreria standard di Swift. Basta import Foundation(o un altro modulo che transitivamente importa Fondazione), gettato il vostro Arraya NSArray, ed è possibile utilizzare molti metodi di ricerca su NSArray.


4

Qualunque di questa soluzione funziona per me

Questa è la soluzione che ho per 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

Se lavori ancora in Swift 1.x

quindi prova,

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

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

1

Per SWIFT 3 puoi usare una semplice funzione

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

Questo darà la posizione del numero, quindi puoi usare like

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

Spero di essere utile


1

SWIFT 4

Diciamo che vuoi memorizzare un numero dall'array chiamato cardButtons in cardNumber, puoi farlo in questo modo:

let cardNumber = cardButtons.index(of: sender)

mittente è il nome del tuo pulsante


0

Swift 4

Per i tipi di riferimento:

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

In Swift 4/5, usa "firstIndex" per trovare l'indice.

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

0

Nel caso qualcuno abbia questo problema

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

fai questo

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

poi

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

0

Per (>= swift 4.0)

È piuttosto molto semplice. Considera il seguente Arrayoggetto.

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

Per ottenere l'indice dell'elemento rose, tutto ciò che devi fare è:

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

Nota:

  • Array.index(of:)restituisce un Optional<Int>.

  • nil implica che l'elemento non è presente nell'array.

  • Potresti voler scartare forzatamente il valore restituito o utilizzare un if-letper aggirare il facoltativo.


0

Usa il metodo firstIndex.

array.firstIndex(where: { $0 == searchedItem })
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.