Como verificar se um elemento está em uma matriz

475

No Swift, como posso verificar se existe um elemento em uma matriz? O Xcode não tem sugestões para contain, includeou has, e uma pesquisa rápida no livro não resultou em nada. Alguma idéia de como verificar isso? Eu sei que existe um método findque retorna o número do índice, mas existe um método que retorna um booleano como o ruby #include??

Exemplo do que eu preciso:

var elements = [1,2,3,4,5]
if elements.contains(5) {
  //do something
}
jaredsmith
fonte
11
if find(elements, 5) != nil { }não é bom o suficiente?
Martin R
1
Eu esperava algo ainda mais limpo, mas não parecia bom. Ainda não encontrei nada na documentação ou no livro.
precisa saber é o seguinte

Respostas:

860

Swift 2, 3, 4, 5:

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

contains()é um método de extensão de protocolo de SequenceType(para seqüências de Equatableelementos) e não um método global como em versões anteriores.

Observações:

Swift versões anteriores:

let elements = [1,2,3,4,5]
if contains(elements, 5) {
    println("yes")
}
Martin R
fonte
4
Alguma documentação sobre esse tipo de funções globais?
Rivera
3
Isso deve funcionar se cada item dentro da matriz (e o item que estamos procurando) for do tipo Dictionary <String, AnyObject>? Tentando conseguir isso, mas recebo um erro em tempo de compilação.
Ppalancica
7
@ppalancica: Isso requer que os elementos da matriz estejam em conformidade com o Equatableprotocolo (o que Dictionary<String, AnyObject>não acontece). Há uma segunda variante do contains()que leva um predicado (compare stackoverflow.com/questions/29679486/... ) talvez você pode usar isso, por exemploif contains(array, { $0 == dict } ) ...
Martin R
Como pesquisar elemento específico da matriz genérica? diga [AnyObject]?
Dhaval H. Nena
127

Para aqueles que vieram aqui procurando uma localização e remover um objeto de uma 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)
}
CãoCafé
fonte
3
Por favor, responda relevante para a pergunta. Esta pergunta apenas pergunta sobre encontrar um elemento na matriz, não removê-lo ou atualizá-lo. Você pode fazer uma pergunta separada e responder você também.
Tejas
60

Use esta extensão:

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

Use como:

array.contains(1)

Atualizado para Swift 2/3

Observe que a partir do Swift 3 (ou mesmo 2), a extensão não é mais necessária, pois a containsfunção global foi transformada em um par de método de extensão ativado Array, o que permite:

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

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

a.contains { $0 < 1 }   // => false
David Berry
fonte
10
encontrar é mais rápido.
Jim Balter
1
dependendo do que você está acostumado, porém, .Contains pode sentir-se mais intuitiva e memorável
Pirijan
4
Você poderia explicar sua sintaxe dividindo-a? Eu nunca vi essa formatação antes e você tem muitas coisas avançadas acontecendo ao mesmo tempo!
Aggressor
40

Se você estiver verificando se uma instância de uma classe ou estrutura personalizada está contida em uma matriz, será necessário implementar o protocolo Equatable antes de poder usar .contains (myObject).

Por exemplo:

struct Cup: Equatable {
    let filled:Bool
}

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

então você pode fazer:

cupArray.contains(myCup)

Dica : a substituição == deve estar no nível global, não dentro da sua classe / estrutura

Andrew Schreiber
fonte
32

Eu usei filtro.

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

Se você quiser, pode compactar isso para

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

Espero que ajude.


Atualização para Swift 2

Hurrah para implementações padrão!

if elements.contains(5) {
    // any matching items are in results
} else {
    // not found
}
Jeffery Thomas
fonte
Gosto da solução de filtro porque você pode usá-la para todo tipo de coisa. Por exemplo, eu estava portando algum código que repetia repetidamente tentando ver se uma lista já tinha um item com um de seus campos contendo um valor de string. É uma linha no Swift, usando um filtro nesse campo.
Maury Markowitz
O filtro é ineficiente porque sempre faz um loop em todos os elementos em vez de retornar imediatamente quando o elemento é encontrado. Melhor usar find ().
quer
19

(Swift 3)

Verifique se existe um elemento em uma matriz (atendendo a alguns critérios) e , se houver, continue trabalhando com o primeiro desses elementos.

Se a intenção for:

  1. Para verificar se um elemento existe em uma matriz (/ preenche alguns critérios booleanos, não necessariamente testes de igualdade),
  2. E, nesse caso, continue e trabalhe com o primeiro desses elementos,

Em seguida, uma alternativa para contains(_:)blueprinted Sequenceé first(where:)de Sequence:

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

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

Neste exemplo, seu uso pode parecer bobo, mas é muito útil se consultar matrizes de tipos de elementos não fundamentais para a existência de quaisquer elementos que atendam a alguma condição. Por exemplo

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.

Quaisquer operações encadeadas usando .filter { ... some condition }.firstpodem ser substituídas favoravelmente por first(where:). O último mostra melhor a intenção e tem vantagens de desempenho em relação a possíveis dispositivos não preguiçosos .filter, pois eles passarão por toda a matriz antes de extrair o (possível) primeiro elemento que passa pelo filtro.


Verifique se existe um elemento em uma matriz (atendendo a alguns critérios) e , se houver, remova o primeiro desses elementos

Um comentário abaixo consulta:

Como posso remover o firstSuchElementda matriz?

Um caso de uso semelhante ao descrito acima é remover o primeiro elemento que atende a um determinado predicado. Para fazer isso, o index(where:)método de Collection(que está prontamente disponível para a coleção de matrizes) pode ser usado para encontrar o índice do primeiro elemento que preenche o predicado, depois o índice pode ser usado com o remove(at:)método de Array(possível; dado que ele existe) remova esse 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"]
}

Ou, se você deseja remover o elemento da matriz e trabalhar com , aplique Optionalo map(_:)método s para usar condicionalmente (para .some(...)retornar de index(where:)) o resultado de index(where:)para remover e capturar o elemento removido da matriz (dentro de uma cláusula de ligação 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
}

Observe que, no exemplo inventado acima, os membros da matriz são tipos simples de valores ( Stringinstâncias), portanto, usar um predicado para encontrar um determinado membro é um exagero , pois podemos simplesmente testar a igualdade usando o index(of:)método mais simples , como mostrado na resposta do @ DogCoffee . Se aplicar a abordagem de localização e remoção acima ao Personexemplo, no entanto, o uso index(where:)com um predicado é apropriado (já que não testamos mais a igualdade, mas o cumprimento de um predicado fornecido).

dfri
fonte
Como posso remover o firstSuchElement da matriz?
i6x86
@ i6x86 obrigado pela pergunta. Atualizei minha resposta com um exemplo de como remover o elemento (e também como remover e capturar o elemento removido).
Dfri
14

A maneira mais simples de fazer isso é usar o filtro na matriz.

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

resultterá o elemento encontrado, se ele existir, e estará vazio se o elemento não existir. Portanto, basta verificar se resultestá vazio para saber se o elemento existe na matriz. Eu usaria o seguinte:

if result.isEmpty {
    // element does not exist in array
} else {
    // element exists
}
davetw12
fonte
ótima solução. portanto, esse método retorna uma matriz. No entanto, estou usando isso para procurar um "id". Na minha aplicação, d's são únicos, portanto, pode haver apenas um resultado. Existe uma maneira de retornar apenas 1 resultado? Estou usando o resultado [0] por enquanto
Dan Beaulieu
3
@ DanBeaulieu Fazer algo como let result = elements.filter { $0==5 }.firstdeve realizar o que você está procurando.
Davidw12
7

Swift 4/5

Outra maneira de conseguir isso é com a função de filtro

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

A partir do Swift 2.1, os NSArrays containsObjectpodem ser usados ​​da seguinte maneira:

if myArray.containsObject(objectImCheckingFor){
    //myArray has the objectImCheckingFor
}
ColossalChris
fonte
4
Na verdade, isso é para um NSArray. Não é uma matriz rápida
Tycho Pandelaar 15/03
Sim, mas você pode converter temporariamente sua matriz rápida em NSArray: se deixe tempNSArrayForChecking = mySwiftArray como NSArray? onde tempNSArrayForChecking.containsObject (objectImCheckingFor) {// myArray tem o objeto}
Vitalii
4

Apenas no caso de alguém tentar descobrir se um indexPathestá entre os selecionados (como em a UICollectionViewou UITableView cellForItemAtIndexPathfunções):

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

Matriz

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

Verificar presença de elementos

elements.contains(5) // true

Obter índice de elementos

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

Obter contagem de elementos

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

Aqui está minha pequena extensão que acabei de escrever para verificar se minha matriz de delegados contém ou não um objeto de delegação ( Swift 2 ). :) Também funciona com tipos de valor como um 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
    }
}

Se você tem uma idéia de como otimizar esse código, informe-me.

DevAndArtist
fonte
2

se o usuário encontrar elementos específicos da matriz, use o código abaixo, igual ao valor inteiro.

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

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

Rápido

Se você não estiver usando o objeto, poderá usar este código para contém.

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

if elements.contains(50) {

   print("true")

}

Se você estiver usando a classe NSObject rapidamente. Essas variáveis ​​estão de acordo com minha exigência. você pode modificar para sua exigência.

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

Isso é para o mesmo tipo de dados.

{ $0.user_id == cliectScreenSelectedObject.user_id }

Se você deseja o tipo AnyObject.

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

Condição completa

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

    cliectScreenSelected.append(cliectScreenSelectedObject)

    print("Object Added")

} else {

    print("Object already exists")

 }
Anit Kumar
fonte
1

que tal usar uma tabela de hash para o trabalho, assim?

primeiro, criando uma função genérica "mapa de hash", estendendo o protocolo 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
    }
}

Essa extensão funcionará desde que os itens da matriz estejam em conformidade com Hashable, como números inteiros ou seqüências de caracteres, aqui está o 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

Mas, por enquanto, vamos nos concentrar apenas em verificar se o elemento está na 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
fonte
0

Swift 4.2 +
Você pode facilmente verificar se a sua instância é uma matriz ou não pela seguinte função.

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

   return false
}

Mesmo você pode acessá-lo da seguinte forma. Você receberá nilse o objeto não for uma matriz.

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

   return nil
}
Kiran Jasvanee
fonte