So überprüfen Sie, ob sich ein Element in einem Array befindet

475

Wie kann ich in Swift überprüfen, ob ein Element in einem Array vorhanden ist? Xcode hat keine Vorschläge für contain, includeoderhas , und eine schnelle Suche im Buch ergab nichts. Irgendeine Idee, wie man das überprüft? Ich weiß, dass es eine Methode findgibt, die die Indexnummer zurückgibt, aber gibt es eine Methode, die einen Booleschen Wert wie den von Ruby zurückgibt #include??

Beispiel für das, was ich brauche:

var elements = [1,2,3,4,5]
if elements.contains(5) {
  //do something
}
Jaredsmith
quelle
11
if find(elements, 5) != nil { }ist nicht gut genug
Martin R
1
Ich hatte auf etwas noch saubereres gehofft, aber es sieht nicht gut aus. Ich habe noch nichts in der Dokumentation oder im Buch gefunden.
Jarmsmith

Antworten:

860

Swift 2, 3, 4, 5:

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

contains()ist eine Protokollerweiterungsmethode von SequenceType(für Sequenzen von EquatableElementen) und keine globale Methode wie in früheren Versionen.

Bemerkungen:

Schnelle ältere Versionen:

let elements = [1,2,3,4,5]
if contains(elements, 5) {
    println("yes")
}
Martin R.
quelle
4
Irgendeine Dokumentation über diese Art von globalen Funktionen?
Rivera
3
Soll dies funktionieren, wenn jedes Element im Array (und das Element, nach dem wir suchen) vom Typ Dictionary <String, AnyObject> ist? Ich versuche das zu erreichen, bekomme aber einen Fehler beim Kompilieren.
ppalancica
7
@ppalancica: Dies erfordert, dass die Array-Elemente dem EquatableProtokoll entsprechen (was Dictionary<String, AnyObject>nicht der Fall ist). Es gibt eine zweite Variante, contains()die ein Prädikat annimmt (vergleiche stackoverflow.com/questions/29679486/… ). Vielleicht können Sie das verwenden, z. B.if contains(array, { $0 == dict } ) ...
Martin R
Wie suche ich ein bestimmtes Element aus einem generischen Array? sag [AnyObject]?
Dhaval H. Nena
127

Für diejenigen, die hierher gekommen sind, um ein Objekt zu finden und aus einem Array zu entfernen:

Schnell 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)
}
DogCoffee
quelle
3
Bitte beantworten Sie die relevante Frage. Bei dieser Frage geht es nur darum, ein Element im Array zu finden, nicht zu entfernen oder zu aktualisieren. Sie können eine separate Frage stellen und diese auch selbst beantworten.
Tejas
60

Verwenden Sie diese Erweiterung:

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

Benutzen als:

array.contains(1)

Aktualisiert für Swift 2/3

Beachten Sie, dass ab Swift 3 (oder sogar 2) die Erweiterung nicht mehr erforderlich ist, da die globale containsFunktion in ein Paar von Erweiterungsmethoden umgewandelt wurde Array, mit denen Sie Folgendes ausführen können:

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

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

a.contains { $0 < 1 }   // => false
David Berry
quelle
10
finden ist schneller.
Jim Balter
1
Je nachdem, was Sie gewohnt sind, fühlen sich .contains möglicherweise intuitiver und einprägsamer an
Pirijan
4
Könnten Sie Ihre Syntax erklären, indem Sie sie aufschlüsseln? Ich habe diese Formatierung noch nie gesehen und Sie haben eine Menge fortgeschrittener Dinge auf einmal!
Aggressor
40

Wenn Sie überprüfen, ob eine Instanz einer benutzerdefinierten Klasse oder Struktur in einem Array enthalten ist, müssen Sie das Equatable- Protokoll implementieren , bevor Sie .contains (myObject) verwenden können.

Zum Beispiel:

struct Cup: Equatable {
    let filled:Bool
}

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

dann können Sie tun:

cupArray.contains(myCup)

Tipp : Die == Überschreibung sollte auf globaler Ebene erfolgen und nicht in Ihrer Klasse / Struktur

Andrew Schreiber
quelle
32

Ich habe Filter verwendet.

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

Wenn Sie möchten, können Sie dies komprimieren

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

Ich hoffe, das hilft.


Update für Swift 2

Hurra für Standardimplementierungen!

if elements.contains(5) {
    // any matching items are in results
} else {
    // not found
}
Jeffery Thomas
quelle
Ich mag die Filterlösung, weil Sie sie für alle möglichen Dinge verwenden können. Zum Beispiel habe ich einen Code portiert, der sich wiederholt und wiederholt hat, um festzustellen, ob eine Liste bereits ein Element enthält, dessen eines Felds einen Zeichenfolgenwert enthält. Es ist eine Zeile in Swift, die einen Filter für dieses Feld verwendet.
Maury Markowitz
Der Filter ist ineffizient, da er immer alle Elemente durchläuft, anstatt sofort zurückzukehren, wenn das Element gefunden wird. Verwenden Sie stattdessen lieber find ().
Thorsten
19

(Swift 3)

Überprüfen Sie, ob ein Element in einem Array vorhanden ist (das einige Kriterien erfüllt), und fahren Sie in diesem Fall mit dem ersten solchen Element fort

Wenn die Absicht ist:

  1. Um zu überprüfen, ob ein Element in einem Array vorhanden ist (/ einige boolesche Kriterien erfüllt, nicht unbedingt Gleichheitstests),
  2. Und wenn ja, fahren Sie fort und arbeiten Sie mit dem ersten solchen Element.

Dann eine Alternative zu contains(_:)als blueprinted Sequenceist first(where:)von Sequence:

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

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

In diesem erfundenen Beispiel mag seine Verwendung albern erscheinen, aber es ist sehr nützlich, wenn Arrays nicht grundlegender Elementtypen nach der Existenz von Elementen abgefragt werden, die eine bestimmte Bedingung erfüllen. Z.B

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.

Alle verketteten Operationen mit .filter { ... some condition }.firstkönnen vorteilhafterweise durch ersetzt werden first(where:). Letzteres zeigt die Absicht besser und hat Leistungsvorteile gegenüber möglichen nicht faulen Geräten von .filter, da diese das gesamte Array passieren, bevor das (mögliche) erste Element, das den Filter passiert, extrahiert wird.


Überprüfen Sie, ob ein Element in einem Array vorhanden ist (das einige Kriterien erfüllt), und entfernen Sie in diesem Fall das erste derartige Element

Ein Kommentar unter Fragen:

Wie kann ich das firstSuchElementaus dem Array entfernen ?

Ein ähnlicher Anwendungsfall wie oben besteht darin , das erste Element zu entfernen, das ein bestimmtes Prädikat erfüllt. Zu diesem Zweck kann die index(where:)Methode von Collection(die für die Array-Sammlung leicht verfügbar ist) verwendet werden, um den Index des ersten Elements zu finden, das das Prädikat erfüllt, wonach der Index mit der remove(at:)Methode von Arrayto (möglich; vorausgesetzt, dass er existiert) verwendet werden kann. Entfernen Sie dieses Element.

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

Wenn Sie das Element aus dem Array entfernen und damit arbeiten möchten , wenden Sie die Optionalfolgende map(_:)Methode an : s , um das Ergebnis von bedingt (für die .some(...)Rückgabe von index(where:)) zu verwenden index(where:), um das entfernte Element aus dem Array zu entfernen und zu erfassen (innerhalb einer optionalen Bindungsklausel). .

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
}

Beachten Sie, dass es sich bei dem erfundenen Beispiel oben um einfache Werttypen ( StringInstanzen) handelt. Die Verwendung eines Prädikats zum Auffinden eines bestimmten Elements ist daher etwas übertrieben , da wir die Gleichheit möglicherweise einfach mit der einfacheren index(of:)Methode testen , wie in der Antwort von @ DogCoffee gezeigt . Wenn Sie jedoch den obigen Find-and-Remove-Ansatz auf das PersonBeispiel anwenden , ist die Verwendung index(where:)mit einem Prädikat angemessen (da wir nicht mehr auf Gleichheit testen, sondern ein angegebenes Prädikat erfüllen).

dfri
quelle
Wie kann ich das firstSuchElement aus dem Array entfernen?
i6x86
@ i6x86 danke für die frage. Ich habe meine Antwort mit einem Beispiel zum Entfernen des Elements (und zum Entfernen und Erfassen des entfernten Elements) aktualisiert.
dfri
14

Der einfachste Weg, dies zu erreichen, ist die Verwendung eines Filters für das Array.

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

resulthat das gefundene Element, wenn es existiert, und ist leer, wenn das Element nicht existiert. Wenn resultSie also einfach überprüfen, ob es leer ist, können Sie feststellen, ob das Element im Array vorhanden ist. Ich würde folgendes verwenden:

if result.isEmpty {
    // element does not exist in array
} else {
    // element exists
}
davetw12
quelle
tolle Lösung. Diese Methode gibt also ein Array zurück. Ich benutze dies jedoch, um nach einer "ID" zu suchen. In meiner Anwendung sind ds eindeutig, daher kann es nur ein Ergebnis geben. Gibt es eine Möglichkeit, nur 1 Ergebnis zurückzugeben? Ich benutze jetzt Ergebnis [0]
Dan Beaulieu
3
@DanBeaulieu Wenn Sie so etwas tun, let result = elements.filter { $0==5 }.firstsollten Sie das erreichen, wonach Sie suchen.
davetw12
7

Swift 4/5

Eine andere Möglichkeit, dies zu erreichen, ist die Filterfunktion

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

Ab Swift 2.1 können NSArrays containsObjectwie folgt verwendet werden:

if myArray.containsObject(objectImCheckingFor){
    //myArray has the objectImCheckingFor
}
ColossalChris
quelle
4
Eigentlich ist das für ein NSArray. Keine schnelle Anordnung
Tycho Pandelaar
Ja, aber Sie können Ihr schnelles Array vorübergehend in NSArray konvertieren: Wenn tempNSArrayForChecking = mySwiftArray als NSArray verwendet wird? wo tempNSArrayForChecking.containsObject (objectImCheckingFor) {// myArray hat das Objekt}
Vitalii
4

Nur für den Fall, dass jemand versucht herauszufinden, ob a indexPathzu den ausgewählten gehört (wie in a UICollectionViewoder UITableView cellForItemAtIndexPathFunktionen):

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

Array

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

Überprüfen Sie das Vorhandensein von Elementen

elements.contains(5) // true

Elementindex abrufen

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

Elementanzahl abrufen

let results = elements.filter { element in element == 5 }
results.count // 2
Sazzad Hissain Khan
quelle
3

Hier ist meine kleine Erweiterung, die ich gerade geschrieben habe, um zu überprüfen, ob mein Delegatenarray ein Delegatenobjekt enthält oder nicht ( Swift 2 ). :) Es funktioniert auch mit Werttypen wie einem Zauber.

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

Wenn Sie eine Idee haben, wie Sie diesen Code optimieren können, lassen Sie es mich einfach wissen.

DevAndArtist
quelle
2

Wenn der Benutzer bestimmte Array-Elemente findet, verwenden Sie den folgenden Code wie den ganzzahligen Wert.

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

 if arrelemnts.contains("test"){
    print("found")   }else{
    print("not found")   }
Yogesh Shelke
quelle
2

Schnell

Wenn Sie kein Objekt verwenden, können Sie diesen Code für enthält verwenden.

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

if elements.contains(50) {

   print("true")

}

Wenn Sie NSObject Class in Swift verwenden. Diese Variablen entsprechen meiner Anforderung. Sie können für Ihre Anforderung ändern.

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

Dies gilt für denselben Datentyp.

{ $0.user_id == cliectScreenSelectedObject.user_id }

Wenn Sie AnyObject eingeben möchten.

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

Voller Zustand

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

    cliectScreenSelected.append(cliectScreenSelectedObject)

    print("Object Added")

} else {

    print("Object already exists")

 }
Anit Kumar
quelle
1

Wie wäre es mit einer Hash-Tabelle für diesen Job?

Erstellen Sie zunächst eine generische Funktion "Hash Map", um das Sequenzprotokoll zu erweitern.

extension Sequence where Element: Hashable {

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

Diese Erweiterung funktioniert, solange die Elemente im Array mit Hashable übereinstimmen, z. B. Ganzzahlen oder Zeichenfolgen. Hier ist die Verwendung ...

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

Aber jetzt konzentrieren wir uns nur darauf, ob sich das Element im Array befindet.

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

print(numExists) // prints true
James Rochabrun
quelle
0

Swift 4.2 + Mit
der folgenden Funktion können Sie leicht überprüfen, ob Ihre Instanz ein Array ist oder nicht.

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

   return false
}

Sogar Sie können wie folgt darauf zugreifen. Sie erhalten, nilwenn das Objekt kein Array wäre.

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

   return nil
}
Kiran Jasvanee
quelle