Jak sprawdzić, czy element jest w tablicy


475

Jak w Swift mogę sprawdzić, czy element istnieje w tablicy? Xcode nie posiada żadnych sugestie contain, includealbo hasi szybkie wyszukiwanie w książce pojawiło się nic. Masz pomysł, jak to sprawdzić? Wiem, że istnieje metoda, findktóra zwraca numer indeksu, ale czy istnieje metoda, która zwraca wartość logiczną jak ruby #include??

Przykład tego, czego potrzebuję:

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

11
if find(elements, 5) != nil { }nie jest wystarczająco dobry?
Martin R

1
Miałem nadzieję na coś jeszcze czystszego, ale nie wygląda dobrze. Nie znalazłem jeszcze nic w dokumentacji ani w książce.
jaredsmith

Odpowiedzi:


860

Swift 2, 3, 4, 5:

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

contains()Jest to metoda rozszerzenie protokołu z SequenceType(dla sekwencji Equatableelementów), a nie jako metoda globalna we wcześniejszych wydaniach.

Uwagi:

Szybkie starsze wersje:

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

4
Jakaś dokumentacja na temat tego rodzaju funkcji globalnych?
Rivera

3
Czy to powinno działać, jeśli każdy element w tablicy (i element, którego szukamy) jest typu Dictionary <String, AnyObject>? Próbuję to osiągnąć, ale pojawia się błąd czasu kompilacji.
ppalancica

7
@ppalancica: Wymaga to, aby elementy tablicy były zgodne z Equatableprotokołem (co Dictionary<String, AnyObject>nie jest zgodne ). Istnieje drugi wariant, contains()który bierze predykat (porównaj stackoverflow.com/questions/29679486/… ), być może możesz go użyć, np.if contains(array, { $0 == dict } ) ...
Martin R

Jak wyszukiwać określony element z tablicy ogólnej? powiedz [AnyObject]?
Dhaval H. Nena

126

Dla tych, którzy tu przybyli w poszukiwaniu znalezienia i usunięcia obiektu z tablicy:

Szybki 1

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

Swift 2

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

Swift 3, 4, 5

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

3
Proszę odpowiedzieć stosownie do pytania. To pytanie dotyczy tylko znalezienia elementu w tablicy, a nie jego usunięcia lub aktualizacji. Możesz zadać osobne pytanie i sam na nie odpowiedzieć.
Tejas,

60

Użyj tego rozszerzenia:

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

Użyj jako:

array.contains(1)

Zaktualizowano dla Swift 2/3

Zauważ, że od Swift 3 (lub nawet 2) rozszerzenie nie jest już konieczne, ponieważ containsfunkcja globalna została przekształcona w parę metod rozszerzenia Array, które umożliwiają wykonanie jednej z następujących czynności:

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

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

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

10
znajdowanie jest szybsze.
Jim Balter

1
w zależności od tego, do czego jesteś przyzwyczajony, .contains może wydawać się bardziej intuicyjny i niezapomniany
Pirijan

4
Czy możesz wyjaśnić swoją składnię, rozkładając ją? Nigdy wcześniej nie widziałem takiego formatowania, a jednocześnie dzieje się wiele zaawansowanych rzeczy!
Agresor

40

Jeśli sprawdzasz, czy wystąpienie niestandardowej klasy lub struktury jest zawarte w tablicy, musisz zaimplementować protokół Equatable , zanim będziesz mógł użyć .contains (myObject).

Na przykład:

struct Cup: Equatable {
    let filled:Bool
}

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

wtedy możesz zrobić:

cupArray.contains(myCup)

Wskazówka : Przesłonięcie == powinno być na poziomie globalnym, a nie w twojej klasie / strukturze


32

Użyłem filtra.

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

Jeśli chcesz, możesz to skompresować

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

Mam nadzieję, że to pomaga.


Aktualizacja dla Swift 2

Hurra na domyślne implementacje!

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

Podoba mi się rozwiązanie filtrujące, ponieważ można go używać do różnych rzeczy. Na przykład przenosiłem jakiś zapętlony i zapętlony kod, próbując sprawdzić, czy lista zawiera już element z jednym z jego pól zawierających wartość ciągu. Jest to jedna linia w Swift, wykorzystująca filtr w tym polu.
Maury Markowitz

filtr jest nieefektywny, ponieważ zawsze zapętla wszystkie elementy zamiast wracać natychmiast po znalezieniu elementu. Zamiast tego lepiej użyć find ().
Thorsten

19

(Swift 3)

Sprawdź, czy element istnieje w tablicy (spełniając pewne kryteria), a jeśli tak, kontynuuj pracę z pierwszym takim elementem

Jeśli celem jest:

  1. Aby sprawdzić, czy element istnieje w tablicy (/ spełnia pewne kryteria boolowskie, niekoniecznie testowanie równości),
  2. A jeśli tak, kontynuuj i pracuj z pierwszym takim elementem,

Wtedy alternatywą contains(_:)jako blueprinted Sequencejest first(where:)od Sequence:

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

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

W tym wymyślonym przykładzie jego użycie może wydawać się głupie, ale jest to bardzo przydatne, jeśli zapytanie o tablice nie fundamentalnych typów elementów o istnienie dowolnego elementu spełniającego jakiś warunek. Na przykład

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.

Wszelkie powiązane operacje przy użyciu .filter { ... some condition }.firstmożna korzystnie zastąpić first(where:). Ta ostatnia pokazuje zamiar lepiej i ma przewagę wydajności w stosunku do możliwych nie leniwych urządzeń .filter, ponieważ przejdą one pełną tablicę przed wyodrębnieniem (możliwego) pierwszego elementu przechodzącego przez filtr.


Sprawdź, czy element istnieje w tablicy (spełniając pewne kryteria), a jeśli tak, usuń pierwszy taki element

Komentarz poniżej zapytań:

Jak mogę usunąć firstSuchElementtablicę?

Podobny przypadek zastosowania do powyższego dotyczy usunięcia pierwszego elementu, który spełnia dany predykat. Aby to zrobić, można zastosować index(where:)metodę Collection(która jest łatwo dostępna w kolekcji tablic) w celu znalezienia indeksu pierwszego elementu spełniającego predykat, po czym indeks można zastosować za pomocą remove(at:)metody Arrayto (możliwe; pod warunkiem, że istnieje) usuń ten 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"]
}

Lub, jeśli chcesz usunąć element z tablicy i pracować z nim , zastosuj metodę Optional: s map(_:), aby warunkowo (do .some(...)zwrotu z index(where:)) użyć wyniku z index(where:)do usunięcia i przechwycenia usuniętego elementu z tablicy (w ramach opcjonalnej klauzuli wiążącej) .

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
}

Zauważ, że w powyższym skonstruowanym przykładzie elementy tablicy są prostymi typami wartości ( Stringinstancjami), więc użycie predykatu w celu znalezienia danego elementu jest nieco przesadzone , ponieważ możemy po prostu przetestować równość przy użyciu prostszej index(of:)metody, jak pokazano w odpowiedzi @ DogCoffee . PersonJednak w przypadku zastosowania powyższego przykładu w znajdowaniu i usuwaniu index(where:)właściwe jest używanie z predykatem (ponieważ nie testujemy już równości, ale spełniamy podany predykat).


Jak mogę usunąć firstSuchElement z tablicy?
i6x86,

@ i6x86 dzięki za pytanie. Zaktualizowałem odpowiedź o przykład usuwania elementu (a także usuwania i przechwytywania usuniętego elementu).
dfri

14

Najprostszym sposobem na osiągnięcie tego jest użycie filtru na tablicy.

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

resultbędzie miał znaleziony element, jeśli istnieje i będzie pusty, jeśli element nie istnieje. Zatem sprawdzenie, czy resultjest puste, powie ci, czy element istnieje w tablicy. Użyłbym następujących:

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

świetne rozwiązanie. więc ta metoda zwraca tablicę. Jednak używam tego do wyszukiwania „identyfikatora”. W mojej aplikacji d są unikalne, więc może być tylko jeden wynik. Czy istnieje sposób na zwrócenie tylko 1 wyniku? Na razie używam wyniku [0]
Dan Beaulieu

3
@DanBeaulieu Robienie czegoś takiego let result = elements.filter { $0==5 }.firstpowinno osiągnąć to, czego szukasz.
davetw12

7

Swift 4/5

Innym sposobem na osiągnięcie tego jest funkcja filtrowania

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

6

Od wersji Swift 2.1 NSArrays containsObjectmożna ich używać w następujący sposób:

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

4
W rzeczywistości dotyczy to NSArray. Nie szybka tablica
Tycho Pandelaar

Tak, ale możesz tymczasowo przekonwertować swoją szybką tablicę na NSArray: jeśli pozwól tempNSArrayForChecking = mySwiftArray jako NSArray? gdzie tempNSArrayForChecking.containsObject (objectImCheckingFor) {// myArray ma obiekt}
Vitalii

4

Tylko w przypadku, ktoś próbuje znaleźć jeśli indexPathjest między wybranymi (jak w sposób UICollectionViewlub UITableView cellForItemAtIndexPathfunkcji):

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

4

Szyk

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

Sprawdź obecność elementów

elements.contains(5) // true

Pobierz indeks elementów

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

Uzyskaj liczbę elementów

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

3

Oto moje małe rozszerzenie, które właśnie napisałem, aby sprawdzić, czy moja tablica delegatów zawiera obiekt delegowany, czy nie ( Swift 2 ). :) Działa również z typami wartości, takimi jak urok.

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

Jeśli masz pomysł, jak zoptymalizować ten kod, daj mi znać.


2

jeśli użytkownik znajdzie określone elementy tablicy, użyj poniższego kodu jako wartości całkowitej.

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

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

2

Szybki

Jeśli nie używasz obiektu, możesz użyć tego kodu dla zawiera.

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

if elements.contains(50) {

   print("true")

}

Jeśli używasz NSObject Class w trybie szybkim. Te zmienne są zgodne z moimi wymaganiami. możesz zmodyfikować według własnych wymagań.

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

Dotyczy to tego samego typu danych.

{ $0.user_id == cliectScreenSelectedObject.user_id }

Jeśli chcesz wpisać AnyObject.

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

Pełny stan

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

    cliectScreenSelected.append(cliectScreenSelectedObject)

    print("Object Added")

} else {

    print("Object already exists")

 }

1

co powiesz na użycie tabeli skrótów dla tego zadania?

po pierwsze, utworzenie ogólnej funkcji „mapy skrótów”, rozszerzającej protokół sekwencji.

extension Sequence where Element: Hashable {

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

To rozszerzenie będzie działać, dopóki elementy w tablicy będą zgodne z Hashable, takie jak liczby całkowite lub ciągi, oto użycie ...

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

Ale na razie skupmy się na sprawdzeniu, czy element znajduje się w tablicy.

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 +
Za pomocą poniższej funkcji możesz łatwo sprawdzić, czy instancja jest tablicą.

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

   return false
}

Nawet ty możesz uzyskać do niego dostęp w następujący sposób. Otrzymasz, niljeśli obiekt nie będzie tablicą.

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

   return nil
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.