Come verificare se un elemento si trova in un array


476

In Swift, come posso verificare se esiste un elemento in un array? Xcode non ha alcun suggerimento per contain, includeo has, e una rapida ricerca nel libro non ha prodotto nulla. Qualche idea su come verificare questo? So che esiste un metodo findche restituisce il numero indice, ma esiste un metodo che restituisce un valore booleano come ruby #include??

Esempio di ciò di cui ho bisogno:

var elements = [1,2,3,4,5]
if elements.contains(5) {
  //do something
}

11
if find(elements, 5) != nil { }non è abbastanza buono?
Martin R,

1
Speravo in qualcosa di ancora più pulito, ma non sembra buono. Non ho ancora trovato nulla nella documentazione o nel libro.
Jaredsmith,

Risposte:


861

Swift 2, 3, 4, 5:

let elements = [1, 2, 3, 4, 5]
if elements.contains(5) {
    print("yes")
}

contains()è un metodo di estensione del protocollo di SequenceType(per sequenze di Equatableelementi) e non un metodo globale come nelle versioni precedenti.

Osservazioni:

Swift versioni precedenti:

let elements = [1,2,3,4,5]
if contains(elements, 5) {
    println("yes")
}

4
Qualche documentazione su questo tipo di funzioni globali?
Rivera,

3
Questo dovrebbe funzionare se ogni elemento all'interno dell'array (e l'elemento che stiamo cercando) è di tipo Dizionario <String, AnyObject>? Sto provando a farlo, ma ottengo un errore di compilazione.
ppalancica,

7
@ppalancica: questo richiede che gli elementi dell'array siano conformi al Equatableprotocollo (che Dictionary<String, AnyObject>non lo fa). C'è una seconda variante di contains()cui prende un predicato (confronta stackoverflow.com/questions/29679486/… ) forse puoi usarlo, ad esempioif contains(array, { $0 == dict } ) ...
Martin R

Come cercare elementi specifici dall'array generico? dire [AnyObject]?
Dhaval H. Nena,

127

Per coloro che sono venuti qui in cerca di una ricerca e rimozione di un oggetto da un array:

Swift 1

if let index = find(itemList, item) {
    itemList.removeAtIndex(index)
}

Swift 2

if let index = itemList.indexOf(item) {
    itemList.removeAtIndex(index)
}

Swift 3, 4

if let index = itemList.index(of: item) {
    itemList.remove(at: index)
}

Swift 5.2

if let index = itemList.firstIndex(of: item) {
    itemList.remove(at: index)
}

3
Si prega di rispondere pertinente alla domanda. Questa domanda chiede solo di trovare un elemento nell'array, non di rimuoverlo o aggiornarlo. Puoi fare una domanda separata e rispondere anche tu.
Tejas,

60

Usa questa estensione:

extension Array {
    func contains<T where T : Equatable>(obj: T) -> Bool {
        return self.filter({$0 as? T == obj}).count > 0
    }
}

Usare come:

array.contains(1)

Aggiornato per Swift 2/3

Si noti che a partire da Swift 3 (o anche 2), l'estensione non è più necessaria poiché la containsfunzione globale è stata trasformata in una coppia di metodi di estensione Array, che consentono di eseguire una delle seguenti operazioni:

let a = [ 1, 2, 3, 4 ]

a.contains(2)           // => true, only usable if Element : Equatable

a.contains { $0 < 1 }   // => false

10
trovare è più veloce.
Jim Balter,

1
a seconda di ciò a cui sei abituato, tuttavia. Contiene può
sembrare

4
Potresti spiegare la tua sintassi scomponendola? Non ho mai visto questa formattazione prima e hai fatto accadere molte cose avanzate contemporaneamente!
Aggressor,

40

Se stai verificando se un'istanza di una classe o struttura personalizzata è contenuta in un array, dovrai implementare il protocollo Equatable prima di poter usare .contains (myObject).

Per esempio:

struct Cup: Equatable {
    let filled:Bool
}

static func ==(lhs:Cup, rhs:Cup) -> Bool { // Implement Equatable
    return lhs.filled == rhs.filled
}

allora puoi fare:

cupArray.contains(myCup)

Suggerimento : l'override == dovrebbe essere a livello globale, non all'interno della tua classe / struttura


32

Ho usato il filtro.

let results = elements.filter { el in el == 5 }
if results.count > 0 {
    // any matching items are in results
} else {
    // not found
}

Se vuoi, puoi comprimerlo in

if elements.filter({ el in el == 5 }).count > 0 {
}

Spero che aiuti.


Aggiornamento per Swift 2

Evviva le implementazioni predefinite!

if elements.contains(5) {
    // any matching items are in results
} else {
    // not found
}

Mi piace la soluzione di filtro perché puoi usarla per ogni sorta di cose. Ad esempio, stavo eseguendo il porting di un codice in loop e in loop cercando di vedere se un elenco aveva già un elemento con uno dei suoi campi che conteneva un valore di stringa. È una riga in Swift, usando un filtro su quel campo.
Maury Markowitz

il filtro è inefficiente perché scorre sempre su tutti gli elementi anziché restituire immediatamente quando viene trovato l'elemento. Meglio usare find () invece.
Thorsten,

19

(Swift 3)

Controlla se esiste un elemento in un array (soddisfacendo alcuni criteri) e, in tal caso, continua a lavorare con il primo di tali elementi

Se l'intento è:

  1. Per verificare se esiste un elemento in un array (/ soddisfa alcuni criteri booleani, non necessariamente test di uguaglianza),
  2. E in tal caso, procedere e lavorare con il primo di tali elementi,

Quindi un'alternativa a contains(_:)come progetto Sequenceè first(where:)di Sequence:

let elements = [1, 2, 3, 4, 5]

if let firstSuchElement = elements.first(where: { $0 == 4 }) {
    print(firstSuchElement) // 4
    // ...
}

In questo esempio inventato, il suo utilizzo potrebbe sembrare sciocco, ma è molto utile se si interrogano array di tipi di elementi non fondamentali per l'esistenza di qualsiasi elemento che soddisfi una condizione. Per esempio

struct Person {
    let age: Int
    let name: String
    init(_ age: Int, _ name: String) {
        self.age = age
        self.name = name
    }
}

let persons = [Person(17, "Fred"),   Person(16, "Susan"),
               Person(19, "Hannah"), Person(18, "Sarah"),
               Person(23, "Sam"),    Person(18, "Jane")]

if let eligableDriver = persons.first(where: { $0.age >= 18 }) {
    print("\(eligableDriver.name) can possibly drive the rental car in Sweden.")
    // ...
} // Hannah can possibly drive the rental car in Sweden.

let daniel = Person(18, "Daniel")
if let sameAgeAsDaniel = persons.first(where: { $0.age == daniel.age }) {
    print("\(sameAgeAsDaniel.name) is the same age as \(daniel.name).")
    // ...
} // Sarah is the same age as Daniel.

Qualsiasi operazione concatenata che utilizza .filter { ... some condition }.firstpuò essere sostituita favorevolmente con first(where:). Quest'ultimo mostra un intento migliore e presenta vantaggi in termini di prestazioni rispetto a possibili dispositivi non pigri .filter, poiché questi passeranno all'intero array prima di estrarre il (possibile) primo elemento che passa attraverso il filtro.


Controllare se esiste un elemento in un array (soddisfacendo alcuni criteri) e, in tal caso, rimuovere il primo di tali elementi

Un commento sotto le domande:

Come posso rimuovere firstSuchElementl'array?

Un caso d'uso simile a quello sopra è quello di rimuovere il primo elemento che soddisfa un dato predicato. Per fare ciò, il index(where:)metodo di Collection(che è prontamente disponibile per la raccolta di array) può essere usato per trovare l'indice del primo elemento che soddisfa il predicato, dopodiché l'indice può essere usato con il remove(at:)metodo di Array(possibile; dato che esiste) rimuovi quell'elemento.

var elements = ["a", "b", "c", "d", "e", "a", "b", "c"]

if let indexOfFirstSuchElement = elements.index(where: { $0 == "c" }) {
    elements.remove(at: indexOfFirstSuchElement)
    print(elements) // ["a", "b", "d", "e", "a", "b", "c"]
}

Oppure, se si desidera rimuovere l'elemento dall'array e lavorare con , applicare Optionalil map(_:)metodo : s per utilizzare in modo condizionale (per il .some(...)ritorno da index(where:)) il risultato da index(where:)per rimuovere e acquisire l'elemento rimosso dall'array (all'interno di una clausola di associazione facoltativa) .

var elements = ["a", "b", "c", "d", "e", "a", "b", "c"]

if let firstSuchElement = elements.index(where: { $0 == "c" })
    .map({ elements.remove(at: $0) }) {

    // if we enter here, the first such element have now been
    // remove from the array
    print(elements) // ["a", "b", "d", "e", "a", "b", "c"]

    // and we may work with it
    print(firstSuchElement) // c
}

Si noti che nell'esempio inventato sopra i membri dell'array sono semplici tipi di valore ( Stringistanze), quindi l'uso di un predicato per trovare un determinato membro è un po 'eccessivo, poiché potremmo semplicemente testare l'uguaglianza usando il index(of:)metodo più semplice come mostrato nella risposta di @ DogCoffee . Se si applica l'approccio trova-rimuovi sopra Personnell'esempio, tuttavia, index(where:)è appropriato l' utilizzo con un predicato (poiché non testiamo più l'uguaglianza ma per soddisfare un predicato fornito).


Come posso rimuovere firstSuchElement dall'array?
i6x86,

@ i6x86 grazie per la domanda. Ho aggiornato la mia risposta con un esempio di come rimuovere l'elemento (e anche come rimuovere e catturare l'elemento rimosso).
venerdì

14

Il modo più semplice per ottenere ciò è utilizzare il filtro sull'array.

let result = elements.filter { $0==5 }

resultavrà l'elemento trovato se esiste e sarà vuoto se l'elemento non esiste. Quindi, semplicemente controllando se resultè vuoto ti dirà se l'elemento esiste nell'array. Vorrei usare quanto segue:

if result.isEmpty {
    // element does not exist in array
} else {
    // element exists
}

ottima soluzione. quindi questo metodo restituisce un array. Tuttavia, sto usando questo per cercare un "id". Nella mia applicazione i d sono unici, quindi può esserci un solo risultato. C'è un modo per restituire solo 1 risultato? Sto usando il risultato [0] per ora
Dan Beaulieu,

3
@DanBeaulieu Fare qualcosa del genere let result = elements.filter { $0==5 }.firstdovrebbe realizzare ciò che stai cercando.
davetw12,

7

Swift 4/5

Un altro modo per raggiungere questo obiettivo è con la funzione filtro

var elements = [1,2,3,4,5]
if let object = elements.filter({ $0 == 5 }).first {
    print("found")
} else {
    print("not found")
}

6

A partire da Swift 2.1 NSArrays containsObjectpuò essere utilizzato in questo modo:

if myArray.containsObject(objectImCheckingFor){
    //myArray has the objectImCheckingFor
}

4
In realtà questo è per un NSArray. Non un array veloce
Tycho Pandelaar,

Sì, ma puoi convertire temporaneamente l'array rapido in NSArray: se lasci tempNSArrayForChecking = mySwiftArray come NSArray? dove tempNSArrayForChecking.containsObject (objectImCheckingFor) {// myArray ha l'oggetto}
Vitalii,

4

Nel caso in cui qualcuno stia cercando di trovare se uno indexPathè tra quelli selezionati (come in a UICollectionViewo UITableView cellForItemAtIndexPathfunzioni):

    var isSelectedItem = false
    if let selectedIndexPaths = collectionView.indexPathsForSelectedItems() as? [NSIndexPath]{
        if contains(selectedIndexPaths, indexPath) {
            isSelectedItem = true
        }
    }

4

Vettore

let elements = [1, 2, 3, 4, 5, 5]

Controlla la presenza degli elementi

elements.contains(5) // true

Ottieni indice degli elementi

elements.firstIndex(of: 5) // 4
elements.firstIndex(of: 10) // nil

Ottieni il conteggio degli elementi

let results = elements.filter { element in element == 5 }
results.count // 2

3

Ecco la mia piccola estensione che ho appena scritto per verificare se il mio array di delegati contiene o meno un oggetto delegato ( Swift 2 ). :) Funziona anche con tipi di valore come un fascino.

extension Array
{
    func containsObject(object: Any) -> Bool
    {
        if let anObject: AnyObject = object as? AnyObject
        {
            for obj in self
            {
                if let anObj: AnyObject = obj as? AnyObject
                {
                    if anObj === anObject { return true }
                }
            }
        }
        return false
    }
}

Se hai un'idea su come ottimizzare questo codice, fammelo sapere.


2

se l'utente trova particolari elementi dell'array, usa sotto il codice lo stesso del valore intero.

var arrelemnts = ["sachin", "test", "test1", "test3"]

 if arrelemnts.contains("test"){
    print("found")   }else{
    print("not found")   }

2

veloce

Se non si utilizza l'oggetto, è possibile utilizzare questo codice per contiene.

let elements = [ 10, 20, 30, 40, 50]

if elements.contains(50) {

   print("true")

}

Se si utilizza la classe NSObject in rapido. Questa variabile è secondo il mio requisito. è possibile modificare per le vostre esigenze.

var cliectScreenList = [ATModelLeadInfo]()
var cliectScreenSelectedObject: ATModelLeadInfo!

Questo è per uno stesso tipo di dati.

{ $0.user_id == cliectScreenSelectedObject.user_id }

Se si desidera digitare AnyObject.

{ "\($0.user_id)" == "\(cliectScreenSelectedObject.user_id)" }

Condizioni complete

if cliectScreenSelected.contains( { $0.user_id == cliectScreenSelectedObject.user_id } ) == false {

    cliectScreenSelected.append(cliectScreenSelectedObject)

    print("Object Added")

} else {

    print("Object already exists")

 }

1

che dire di usare una tabella hash per il lavoro, in questo modo?

in primo luogo, creando una funzione generica "hash map", estendendo il protocollo Sequence.

extension Sequence where Element: Hashable {

    func hashMap() -> [Element: Int] {
        var dict: [Element: Int] = [:]
        for (i, value) in self.enumerated() {
            dict[value] = i
        }
        return dict
    }
}

Questa estensione funzionerà finché gli elementi dell'array sono conformi a Hashable, come numeri interi o stringhe, ecco l'uso ...

let numbers = Array(0...50) 
let hashMappedNumbers = numbers.hashMap()

let numToDetect = 35

let indexOfnumToDetect = hashMappedNumbers[numToDetect] // returns the index of the item and if all the elements in the array are different, it will work to get the index of the object!

print(indexOfnumToDetect) // prints 35

Ma per ora, concentriamoci sul controllo se l'elemento è nella matrice.

let numExists = indexOfnumToDetect != nil // if the key does not exist 
means the number is not contained in the collection.

print(numExists) // prints true

0

Swift 4.2 +
Puoi facilmente verificare che la tua istanza sia un array o meno con la seguente funzione.

func verifyIsObjectOfAnArray<T>(_ object: T) -> Bool {
   if let _ = object as? [T] {
      return true
   }

   return false
}

Anche tu puoi accedervi come segue. Riceverai nilse l'oggetto non sarebbe un array.

func verifyIsObjectOfAnArray<T>(_ object: T) -> [T]? {
   if let array = object as? [T] {
      return array
   }

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