How to check if an element is in an array

后端 未结 17 974
囚心锁ツ
囚心锁ツ 2020-11-22 10:24

In Swift, how can I check if an element exists in an array? Xcode does not have any suggestions for contain, include, or has, and a qu

相关标签:
17条回答
  • 2020-11-22 10:44

    Swift 2, 3, 4, 5:

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

    contains() is a protocol extension method of SequenceType (for sequences of Equatable elements) and not a global method as in earlier releases.

    Remarks:

    • This contains() method requires that the sequence elements adopt the Equatable protocol, compare e.g. Andrews's answer.
    • If the sequence elements are instances of a NSObject subclass then you have to override isEqual:, see NSObject subclass in Swift: hash vs hashValue, isEqual vs ==.
    • There is another – more general – contains() method which does not require the elements to be equatable and takes a predicate as an argument, see e.g. Shorthand to test if an object exists in an array for Swift?.

    Swift older versions:

    let elements = [1,2,3,4,5]
    if contains(elements, 5) {
        println("yes")
    }
    
    0 讨论(0)
  • 2020-11-22 10:47

    If you are checking if an instance of a custom class or struct is contained in an array, you'll need to implement the Equatable protocol before you can use .contains(myObject).

    For example:

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

    then you can do:

    cupArray.contains(myCup)
    

    Tip: The == override should be at the global level, not within your class/struct

    0 讨论(0)
  • 2020-11-22 10:48

    For those who came here looking for a find and remove an object from an array:

    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)
    }
    
    0 讨论(0)
  • 2020-11-22 10:49

    what about using a hash table for the job, like this?

    first, creating a "hash map" generic function, extending the Sequence protocol.

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

    This extension will work as long as the items in the array conform to Hashable, like integers or strings, here is the usage...

    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
    

    But for now, let's just focus in check if the element is in the array.

    let numExists = indexOfnumToDetect != nil // if the key does not exist 
    means the number is not contained in the collection.
    
    print(numExists) // prints true
    
    0 讨论(0)
  • 2020-11-22 10:50

    Swift 4/5

    Another way to achieve this is with the filter function

    var elements = [1,2,3,4,5]
    if let object = elements.filter({ $0 == 5 }).first {
        print("found")
    } else {
        print("not found")
    }
    
    0 讨论(0)
  • 2020-11-22 10:51

    (Swift 3)

    Check if an element exists in an array (fulfilling some criteria), and if so, proceed working with the first such element

    If the intent is:

    1. To check whether an element exist in an array (/fulfils some boolean criteria, not necessarily equality testing),
    2. And if so, proceed and work with the first such element,

    Then an alternative to contains(_:) as blueprinted Sequence is to first(where:) of Sequence:

    let elements = [1, 2, 3, 4, 5]
    
    if let firstSuchElement = elements.first(where: { $0 == 4 }) {
        print(firstSuchElement) // 4
        // ...
    }
    

    In this contrived example, its usage might seem silly, but it's very useful if querying arrays of non-fundamental element types for existence of any elements fulfilling some condition. E.g.

    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.
    

    Any chained operations using .filter { ... some condition }.first can favourably be replaced with first(where:). The latter shows intent better, and have performance advantages over possible non-lazy appliances of .filter, as these will pass the full array prior to extracting the (possible) first element passing the filter.


    Check if an element exists in an array (fulfilling some criteria), and if so, remove the first such element

    A comment below queries:

    How can I remove the firstSuchElement from the array?

    A similar use case to the one above is to remove the first element that fulfils a given predicate. To do so, the index(where:) method of Collection (which is readily available to array collection) may be used to find the index of the first element fulfilling the predicate, whereafter the index can be used with the remove(at:) method of Array to (possible; given that it exists) remove that 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"]
    }
    

    Or, if you'd like to remove the element from the array and work with, apply Optional:s map(_:) method to conditionally (for .some(...) return from index(where:)) use the result from index(where:) to remove and capture the removed element from the array (within an optional binding clause).

    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
    }
    

    Note that in the contrived example above the array members are simple value types (String instances), so using a predicate to find a given member is somewhat over-kill, as we might simply test for equality using the simpler index(of:) method as shown in @DogCoffee's answer. If applying the find-and-remove approach above to the Person example, however, using index(where:) with a predicate is appropriate (since we no longer test for equality but for fulfilling a supplied predicate).

    0 讨论(0)
提交回复
热议问题