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.