Cómo verificar si un elemento está en una matriz

476

En Swift, ¿cómo puedo verificar si un elemento existe en una matriz? Xcode no tiene ninguna sugerencia para contain, includeo has, y una búsqueda rápida a través del libro resultó en nada. ¿Alguna idea de cómo verificar esto? Sé que hay un método findque devuelve el número de índice, pero ¿hay algún método que devuelva un valor booleano como el de Ruby #include??

Ejemplo de lo que necesito:

var elements = [1,2,3,4,5]
if elements.contains(5) {
  //do something
}
jaredsmith
fuente
11
if find(elements, 5) != nil { }¿No es suficientemente bueno?
Martin R
1
Esperaba algo aún más limpio, pero no se ve bien. No he encontrado nada en la documentación o el libro todavía.
jaredsmith

Respuestas:

861

Swift 2, 3, 4, 5:

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

contains()es un método de extensión de protocolo de SequenceType(para secuencias de Equatableelementos) y no un método global como en versiones anteriores.

Observaciones:

Versiones anteriores de Swift:

let elements = [1,2,3,4,5]
if contains(elements, 5) {
    println("yes")
}
Martin R
fuente
44
¿Alguna documentación sobre este tipo de funciones globales?
Rivera
3
¿Se supone que esto funciona si cada elemento dentro de la matriz (y el elemento que estamos buscando) es del tipo Dictionary <String, AnyObject>? Tratando de lograr eso, pero obtengo un error en tiempo de compilación.
ppalancica
77
@ppalancica: Esto requiere que los elementos de la matriz se ajusten al Equatableprotocolo (que Dictionary<String, AnyObject>no lo hace). Hay una segunda variante de la contains()cual toma un predicado (compare stackoverflow.com/questions/29679486/… ) tal vez pueda usar eso, por ejemploif contains(array, { $0 == dict } ) ...
Martin R
¿Cómo buscar un elemento específico de una matriz genérica? decir [AnyObject]?
Dhaval H. Nena
127

Para aquellos que vinieron aquí buscando un hallazgo y eliminar un objeto de una matriz:

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)
}
PerroCafé
fuente
3
Por favor conteste relevante a la pregunta. Esta pregunta solo pregunta sobre encontrar un elemento en la matriz, no eliminarlo o actualizarlo. Puede plantear una pregunta por separado y responderla usted mismo también.
Tejas
60

Usa esta extensión:

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

Usar como:

array.contains(1)

Actualizado para Swift 2/3

Tenga en cuenta que a partir de Swift 3 (o incluso 2), la extensión ya no es necesaria ya que la containsfunción global se ha convertido en un par de métodos de extensión activados Array, que le permiten realizar cualquiera de:

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

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

a.contains { $0 < 1 }   // => false
David Berry
fuente
10
encontrar es más rápido
Jim Balter
1
Sin embargo, dependiendo de lo que esté acostumbrado, .contains puede parecer más intuitivo y memorable
Pirijan
44
¿Podría explicar su sintaxis desglosándola? ¡Nunca antes había visto este formato y tienes muchas cosas avanzadas sucediendo a la vez!
Agresor
40

Si está verificando si una instancia de una clase o estructura personalizada está contenida en una matriz, deberá implementar el protocolo Equatable antes de poder usar .contains (myObject).

Por ejemplo:

struct Cup: Equatable {
    let filled:Bool
}

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

entonces puedes hacer:

cupArray.contains(myCup)

Consejo : La anulación == debe estar a nivel global, no dentro de su clase / estructura

Andrew Schreiber
fuente
32

Usé filtro

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

Si quieres, puedes comprimir eso para

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

Espero que ayude.


Actualización para Swift 2

¡Hurra por las implementaciones predeterminadas!

if elements.contains(5) {
    // any matching items are in results
} else {
    // not found
}
Jeffery Thomas
fuente
Me gusta la solución de filtro porque puedes usarla para todo tipo de cosas. Por ejemplo, estaba transfiriendo un código que giraba y giraba tratando de ver si una lista ya tenía un elemento con uno de sus campos que contenía un valor de cadena. Es una línea en Swift, que usa un filtro en ese campo.
Maury Markowitz
El filtro es ineficiente porque siempre recorre todos los elementos en lugar de regresar inmediatamente cuando se encuentra el elemento. Mejor use find () en su lugar.
Thorsten
19

(Swift 3)

Verifique si un elemento existe en una matriz (cumpliendo algunos criterios), y si es así, continúe trabajando con el primer elemento

Si la intención es:

  1. Para verificar si un elemento existe en una matriz (/ cumple algunos criterios booleanos, no necesariamente pruebas de igualdad),
  2. Y si es así, proceda y trabaje con el primer elemento,

Entonces, una alternativa a contains(_:)blueprinted Sequencees first(where:)de Sequence:

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

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

En este ejemplo artificial, su uso puede parecer tonto, pero es muy útil si se consultan matrices de tipos de elementos no fundamentales para la existencia de cualquier elemento que cumpla alguna condición. P.ej

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.

Cualquier operación encadenada usando .filter { ... some condition }.firstpuede ser reemplazada favorablemente por first(where:). Este último muestra una mejor intención y tiene ventajas de rendimiento sobre los posibles dispositivos no perezosos .filter, ya que estos pasarán la matriz completa antes de extraer el (posible) primer elemento que pasa el filtro.


Compruebe si existe un elemento en una matriz (cumpliendo algunos criterios) y , de ser así, elimine el primer elemento

Un comentario debajo de las consultas:

¿Cómo puedo eliminar el firstSuchElementde la matriz?

Un caso de uso similar al anterior es eliminar el primer elemento que cumple un predicado dado. Para hacerlo, el index(where:)método de Collection(que está fácilmente disponible para la colección de matrices) puede usarse para encontrar el índice del primer elemento que cumple el predicado, después de lo cual el índice puede usarse con el remove(at:)método de Arrayto (posible; dado que existe) eliminar ese 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"]
}

O, si desea eliminar el elemento de la matriz y trabajar con él , aplique Optionalel map(_:)método : s para usar condicionalmente (para .some(...)regresar de index(where:)) el resultado de index(where:)eliminar y capturar el elemento eliminado de la matriz (dentro de una cláusula de enlace opcional) .

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
}

Tenga en cuenta que en el ejemplo artificial anterior, los miembros de la matriz son tipos de valores simples ( Stringinstancias), por lo que usar un predicado para encontrar un miembro dado es algo excesivo, ya que podríamos simplemente probar la igualdad usando el index(of:)método más simple como se muestra en la respuesta de @ DogCoffee . PersonSin embargo, si aplica el enfoque de buscar y eliminar anterior al ejemplo, usarlo index(where:)con un predicado es apropiado (ya que ya no probamos la igualdad sino el cumplimiento de un predicado proporcionado).

dfri
fuente
¿Cómo puedo eliminar firstSuchElement de la matriz?
i6x86
@ i6x86 gracias por la pregunta. Actualicé mi respuesta con un ejemplo de cómo eliminar el elemento (y también cómo eliminar y capturar el elemento eliminado).
dfri
14

La forma más sencilla de lograr esto es usar filtro en la matriz.

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

resulttendrá el elemento encontrado si existe y estará vacío si el elemento no existe. Entonces, simplemente verificar si resultestá vacío le dirá si el elemento existe en la matriz. Yo usaría lo siguiente:

if result.isEmpty {
    // element does not exist in array
} else {
    // element exists
}
davetw12
fuente
Gran solución. entonces este método devuelve una matriz. Sin embargo, estoy usando esto para buscar un "id". En mi aplicación, los d son únicos, por lo que solo puede haber un resultado. ¿Hay alguna manera de devolver solo 1 resultado? Estoy usando el resultado [0] por ahora
Dan Beaulieu
3
@DanBeaulieu Hacer algo como let result = elements.filter { $0==5 }.firstdebería lograr lo que estás buscando.
davetw12
7

Swift 4/5

Otra forma de lograr esto es con la función de filtro

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

A partir de Swift 2.1, las matrices NSA containsObjectpueden usarse de la siguiente manera:

if myArray.containsObject(objectImCheckingFor){
    //myArray has the objectImCheckingFor
}
ColosalChris
fuente
44
En realidad eso es para un NSArray. No es una serie rápida
Tycho Pandelaar
Sí, pero puede convertir temporalmente su matriz rápida a NSArray: si deja tempNSArrayForChecking = mySwiftArray como NSArray? donde tempNSArrayForChecking.containsObject (objectImCheckingFor) {// myArray tiene el objeto}
Vitalii
4

En caso de que alguien esté tratando de encontrar si un indexPathestá entre los seleccionados (como en una UICollectionViewo UITableView cellForItemAtIndexPathfunciones):

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

Formación

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

Verificar presencia de elementos

elements.contains(5) // true

Obtener índice de elementos

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

Obtener recuento de elementos

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

Aquí está mi pequeña extensión que acabo de escribir para verificar si mi matriz de delegado contiene un objeto delegado o no ( Swift 2 ). :) También funciona con tipos de valor como un encanto.

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 tiene una idea de cómo optimizar este código, hágamelo saber.

DevAndArtist
fuente
2

si el usuario encuentra elementos de matriz particulares, use el código siguiente igual que el valor entero.

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

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

Rápido

Si no está utilizando un objeto, puede usar este código para contiene.

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

if elements.contains(50) {

   print("true")

}

Si está utilizando la clase NSObject en Swift. Esta variable es de acuerdo a mi requerimiento. Puede modificar para su requisito.

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

Esto es para un mismo tipo de datos.

{ $0.user_id == cliectScreenSelectedObject.user_id }

Si desea escribir AnyObject.

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

Condición completa

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

    cliectScreenSelected.append(cliectScreenSelectedObject)

    print("Object Added")

} else {

    print("Object already exists")

 }
Anit Kumar
fuente
1

¿Qué pasa con el uso de una tabla hash para el trabajo, como este?

primero, creando una función genérica de "mapa hash", extendiendo el protocolo de secuencia.

extension Sequence where Element: Hashable {

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

Esta extensión funcionará siempre que los elementos de la matriz se ajusten a Hashable, como enteros o cadenas, aquí está el 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

Pero por ahora, concentrémonos en verificar si el elemento está en la matriz.

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
fuente
0

Swift 4.2 +
Puede verificar fácilmente si su instancia es una matriz o no mediante la siguiente función.

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

   return false
}

Incluso puedes acceder de la siguiente manera. Recibirá nilsi el objeto no sería una matriz.

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

   return nil
}
Kiran Jasvanee
fuente