Comment vérifier si un élément est dans un tableau

476

Dans Swift, comment puis-je vérifier si un élément existe dans un tableau? Xcode n'a pas de suggestions pour contain, includeou has, et une recherche rapide à travers le livre n'a rien donné . Une idée comment vérifier cela? Je sais qu'il existe une méthode findqui renvoie le numéro d'index, mais existe-t-il une méthode qui renvoie un booléen comme Ruby #include??

Exemple de ce dont j'ai besoin:

var elements = [1,2,3,4,5]
if elements.contains(5) {
  //do something
}
jaredsmith
la source
11
if find(elements, 5) != nil { }n'est pas assez bon?
Martin R
1
J'espérais quelque chose d'encore plus propre, mais ce n'est pas beau. Je n'ai encore rien trouvé dans la documentation ou le livre.
jaredsmith

Réponses:

861

Swift 2, 3, 4, 5:

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

contains()est une méthode d'extension de protocole de SequenceType(pour les séquences d' Equatableéléments) et non une méthode globale comme dans les versions précédentes.

Remarques:

Swift anciennes versions:

let elements = [1,2,3,4,5]
if contains(elements, 5) {
    println("yes")
}
Martin R
la source
4
Une documentation sur ce type de fonctions globales?
Rivera
3
Est-ce censé fonctionner si chaque élément à l'intérieur du tableau (et l'élément que nous recherchons) est de type Dictionary <String, AnyObject>? J'essaie d'y parvenir mais j'obtiens une erreur au moment de la compilation.
ppalancica
7
@ppalancica: Cela nécessite que les éléments du tableau soient conformes au Equatableprotocole (ce qui Dictionary<String, AnyObject>n'est pas le cas). Il existe une deuxième variante contains()qui prend un prédicat (comparer stackoverflow.com/questions/29679486/… ) peut-être que vous pouvez l'utiliser, par exempleif contains(array, { $0 == dict } ) ...
Martin R
Comment rechercher un élément spécifique à partir d'un tableau générique? dites [AnyObject]?
Dhaval H.Nena
127

Pour ceux qui sont venus ici à la recherche d'une recherche et supprimer un objet d'un tableau:

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)
}
DogCoffee
la source
3
Veuillez répondre à la question. Cette question demande simplement de trouver un élément dans un tableau, pas de le supprimer ou de le mettre à jour. Vous pouvez également poser une question distincte et y répondre vous-même.
Tejas
60

Utilisez cette extension:

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

Utilisé comme:

array.contains(1)

Mis à jour pour Swift 2/3

Notez que depuis Swift 3 (ou même 2), l'extension n'est plus nécessaire car la containsfonction globale a été transformée en une paire de méthodes d'extension Array, ce qui vous permet de faire l'une des choses suivantes:

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

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

a.contains { $0 < 1 }   // => false
David Berry
la source
10
trouver est plus rapide.
Jim Balter
1
selon ce à quoi vous êtes habitué, .contains peut sembler plus intuitif et mémorable
Pirijan
4
Pourriez-vous expliquer votre syntaxe en la décomposant? Je n'ai jamais vu ce formatage auparavant et vous avez beaucoup de choses avancées en même temps!
Aggressor
40

Si vous vérifiez si une instance d'une classe ou d'une structure personnalisée est contenue dans un tableau, vous devrez implémenter le protocole Equatable avant de pouvoir utiliser .contains (myObject).

Par exemple:

struct Cup: Equatable {
    let filled:Bool
}

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

alors vous pouvez faire:

cupArray.contains(myCup)

Astuce : la substitution == doit être au niveau global, pas dans votre classe / structure

Andrew Schreiber
la source
32

J'ai utilisé un filtre.

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

Si vous le souhaitez, vous pouvez le compresser en

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

J'espère que cela pourra aider.


Mise à jour pour Swift 2

Vive les implémentations par défaut!

if elements.contains(5) {
    // any matching items are in results
} else {
    // not found
}
Jeffery Thomas
la source
J'aime la solution de filtrage car vous pouvez l'utiliser pour toutes sortes de choses. Par exemple, je portais du code en boucle et en boucle en essayant de voir si une liste avait déjà un élément avec l'un de ses champs contenant une valeur de chaîne. C'est une ligne dans Swift, utilisant un filtre sur ce champ.
Maury Markowitz
le filtre est inefficace car il boucle toujours sur tous les éléments au lieu de revenir immédiatement lorsque l'élément est trouvé. Mieux vaut utiliser find () à la place.
Thorsten
19

(Swift 3)

Vérifiez si un élément existe dans un tableau (remplissant certains critères), et si oui, continuez à travailler avec le premier élément de ce type

Si l'intention est:

  1. Pour vérifier si un élément existe dans un tableau (/ remplit certains critères booléens, pas nécessairement des tests d'égalité),
  2. Et si oui, continuez et travaillez avec le premier élément de ce type,

Alors une alternative à contains(_:)as blueprinted Sequenceest first(where:)de Sequence:

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

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

Dans cet exemple artificiel, son utilisation peut sembler stupide, mais il est très utile si vous interrogez des tableaux de types d'éléments non fondamentaux pour l'existence de tout élément remplissant une condition. Par exemple

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.

Toute opération chaînée utilisant .filter { ... some condition }.firstpeut avantageusement être remplacée par first(where:). Ce dernier montre mieux l'intention et présente des avantages en termes de performances par rapport aux éventuels appareils non paresseux .filter, car ceux-ci passeront le tableau complet avant d'extraire le premier élément (possible) passant le filtre.


Vérifiez si un élément existe dans un tableau (remplissant certains critères), et si oui, supprimez le premier élément de ce type

Un commentaire ci-dessous interroge:

Comment puis-je supprimer le firstSuchElementdu tableau?

Un cas d'utilisation similaire à celui ci-dessus consiste à supprimer le premier élément qui remplit un prédicat donné. Pour ce faire, la index(where:)méthode de Collection(qui est facilement disponible pour la collection de tableaux) peut être utilisée pour trouver l'index du premier élément remplissant le prédicat, après quoi l'index peut être utilisé avec la remove(at:)méthode de Array(possible; étant donné qu'il existe) supprimer cet élément.

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

Ou, si vous souhaitez supprimer l'élément du tableau et travailler avec , appliquez la méthode Optional: s map(_:)à conditionnellement (pour le .some(...)retour de index(where:)) utiliser le résultat de index(where:)pour supprimer et capturer l'élément supprimé du tableau (dans une clause de liaison facultative) .

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
}

Notez que dans l'exemple artificiel ci-dessus, les membres du tableau sont des types de valeur simples ( Stringinstances), donc l'utilisation d'un prédicat pour trouver un membre donné est quelque peu exagérée , car nous pourrions simplement tester l'égalité en utilisant la index(of:)méthode la plus simple comme indiqué dans la réponse de @ DogCoffee . PersonCependant, si vous appliquez l'approche find-and-remove ci-dessus à l' exemple, l'utilisation index(where:)avec un prédicat est appropriée (puisque nous ne testons plus l'égalité mais pour remplir un prédicat fourni).

dfri
la source
Comment puis-je supprimer le firstSuchElement du tableau?
i6x86
@ i6x86 merci pour la question. J'ai mis à jour ma réponse avec un exemple de comment supprimer l'élément (et aussi comment supprimer et capturer l'élément supprimé).
dfri
14

La façon la plus simple d'y parvenir est d'utiliser un filtre sur le tableau.

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

resultaura l'élément trouvé s'il existe et sera vide si l'élément n'existe pas. Donc, vérifier simplement si resultest vide vous dira si l'élément existe dans le tableau. J'utiliserais ce qui suit:

if result.isEmpty {
    // element does not exist in array
} else {
    // element exists
}
davetw12
la source
excellente solution. cette méthode renvoie donc un tableau. Cependant, j'utilise ceci pour rechercher un "id". Dans ma demande, les d sont uniques, il ne peut donc y avoir qu'un seul résultat. Existe-t-il un moyen de renvoyer un seul résultat? J'utilise result [0] pour l'instant
Dan Beaulieu
3
@DanBeaulieu Faire quelque chose comme ça let result = elements.filter { $0==5 }.firstdevrait accomplir ce que vous cherchez.
davetw12
7

Swift 4/5

Une autre façon d'y parvenir est avec la fonction de filtre

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

Depuis Swift 2.1, les NSArrays containsObjectpeuvent être utilisés comme suit :

if myArray.containsObject(objectImCheckingFor){
    //myArray has the objectImCheckingFor
}
ColossalChris
la source
4
En fait, c'est pour un NSArray. Pas un tableau rapide
Tycho Pandelaar
Oui, mais vous pouvez temporairement convertir votre tableau Swift en NSArray: si laissez tempNSArrayForChecking = mySwiftArray en tant que NSArray? où tempNSArrayForChecking.containsObject (objectImCheckingFor) {// myArray a l'objet}
Vitalii
4

Juste au cas où quelqu'un essaierait de trouver si an indexPathest parmi ceux sélectionnés (comme dans a UICollectionViewou UITableView cellForItemAtIndexPathfonctions):

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

Array

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

Vérifier la présence des éléments

elements.contains(5) // true

Obtenir l'index des éléments

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

Obtenir le nombre d'éléments

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

Voici ma petite extension que je viens d'écrire pour vérifier si mon tableau délégué contient ou non un objet délégué ( Swift 2 ). :) Il fonctionne également avec des types de valeur comme un charme.

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

Si vous avez une idée comment optimiser ce code, faites-le moi savoir.

DevAndArtist
la source
2

si l'utilisateur trouve des éléments de tableau particuliers, utilisez le code ci-dessous comme valeur entière.

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

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

Rapide

Si vous n'utilisez pas d'objet, vous pouvez utiliser ce code pour contient.

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

if elements.contains(50) {

   print("true")

}

Si vous utilisez NSObject Class dans swift. Cette variable est selon mes besoins. vous pouvez modifier selon vos besoins.

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

C'est pour un même type de données.

{ $0.user_id == cliectScreenSelectedObject.user_id }

Si vous souhaitez taper AnyObject.

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

État complet

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

    cliectScreenSelected.append(cliectScreenSelectedObject)

    print("Object Added")

} else {

    print("Object already exists")

 }
Anit Kumar
la source
1

qu'en est-il de l'utilisation d'une table de hachage pour le travail, comme ça?

tout d'abord, en créant une fonction générique de "carte de hachage", étendant le protocole de séquence.

extension Sequence where Element: Hashable {

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

Cette extension fonctionnera tant que les éléments du tableau seront conformes à Hashable, comme les entiers ou les chaînes, voici l'utilisation ...

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

Mais pour l'instant, concentrons-nous juste pour vérifier si l'élément est dans le tableau.

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
la source
0

Swift 4.2 +
Vous pouvez facilement vérifier que votre instance est un tableau ou non par la fonction suivante.

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

   return false
}

Même vous pouvez y accéder comme suit. Vous recevrez nilsi l'objet ne serait pas un tableau.

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

   return nil
}
Kiran Jasvanee
la source