ChatGPT解决这个技术问题 Extra ChatGPT

How to check if an element is in an array

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 quick search through the book turned up nothing. Any idea how to check for this? I know that there is a method find that returns the index number, but is there a method that returns a boolean like ruby's #include??

Example of what I need:

var elements = [1,2,3,4,5]
if elements.contains(5) {
  //do something
}
if find(elements, 5) != nil { } is not good enough?
I was hoping for something even cleaner, but its not looking good. I haven't found anything in the documentation or the book yet.

S
Sazzad Hissain Khan

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

Any documentation about this kind of global functions?
Is this supposed to work if each item inside the array (and the item we are searching for) is of type Dictionary? Trying to achieve that but I get compile-time error.
@ppalancica: This requires that the array elements conform to the Equatable protocol (which Dictionary<String, AnyObject> doesn't). There is a second variant of contains() which takes a predicate (compare stackoverflow.com/questions/29679486/…) perhaps you can use that, e.g. if contains(array, { $0 == dict } ) ...
How to search specific element from generic array? say [AnyObject] ?
J
Joannes

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

D
David Berry

Updated for Swift 2+

Note that as of Swift 3 (or even 2), the extension below is no longer necessary as the global contains function has been made into a pair of extension method on Array, which allow you to do either of:

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

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

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

Historical Answer for Swift 1:

Use this extension: (updated to Swift 5.2)

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

Use as:

array.contains(1)

depending on what you're used to though, .contains may feel more intuitive and memorable
Could you explain your syntax by breaking it down? I've never seen this formatting before and you've got a lot of advanced stuff happening at once!
I changed the original code to use .isEmpty as it is a practice suggested by SwiftLint.
Don't use this extension, it's horrible. Just use developer.apple.com/documentation/swift/array/2945493-contains
Great when people with no concept of the history of the language make judgements like this. Note the section on "Updated for Swift 2/3" that's when contains was added to the language.
a
andrewtweber

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


Attention: This does not check whether an instance of a custom class or struct is in the array. It checks whether there is an element that evaluates its == operator as true given the param to contains() to compare with. Example: An array of pointer wrapper objects that implement == to return whether both objects point to the same memory address would completely break this solution.
J
Jeffery Thomas

I used filter.

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

If you want, you can compress that to

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

Hope that helps.

Update for Swift 2

Hurray for default implementations!

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

I like the filter solution because you can use it for all sorts of things. For instance, I was porting some code that looped and looped trying to see if a list already had an item with one of it's fields containing a string value. It's one line in Swift, using a filter on that field.
filter is inefficient because it always loops over all elements instead of returning immediately when the element is found. Better use find() instead.
C
Community

(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:

To check whether an element exist in an array (/fulfils some boolean criteria, not necessarily equality testing), 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).


How can I remove the firstSuchElement from the array?
@i6x86 thanks for the question. I updated my answer with an example of how to remove the element (and also how to remove and capture the removed element).
d
davetw12

The simplest way to accomplish this is to use filter on the array.

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

result will have the found element if it exists and will be empty if the element does not exist. So simply checking if result is empty will tell you whether the element exists in the array. I would use the following:

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

great solution. so this method returns an array. However, I'm using this to look for an "id". In my application d's are unique, so there can be only one result. Is there a way to return just 1 result? I'm using result[0] for now
@DanBeaulieu Doing something like let result = elements.filter { $0==5 }.first should accomplish what you're looking for.
@davetw12 No. This would unnecessarily iterate the whole collection. Better to use first(where: predicate).
H
Honcharov Anton

An array that contains a property that equals to

yourArray.contains(where: {$0.propertyToCheck == value })

Returns boolean.


i
iOSArchitect.com

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

This would unnecessarily iterate the whole collection. This is definitely the wrong approach.
C
Chris Klingler

As of Swift 2.1 NSArrays have containsObjectthat can be used like so:

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

Actually that is for an NSArray. Not a swift array
Yeah, but you can temporary convert your swift array to NSArray: if let tempNSArrayForChecking = mySwiftArray as NSArray? where tempNSArrayForChecking.containsObject(objectImCheckingFor) {//myArray has the object }
C
Community

Array

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

Check elements presence

elements.contains(5) // true

Get elements index

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

Get element count

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

A
Ali

Just in case anybody is trying to find if an indexPath is among the selected ones (like in a UICollectionView or UITableView cellForItemAtIndexPath functions):

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

Y
Yogesh shelke

if user find particular array elements then use below code same as integer value.

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

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

D
DevAndArtist

Here is my little extension I just wrote to check if my delegate array contains a delegate object or not (Swift 2). :) It Also works with value types like a charm.

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

If you have an idea how to optimize this code, than just let me know.


A
Anit Kumar

Swift

If you are not using object then you can user this code for contains.

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

if elements.contains(50) {

   print("true")

}

If you are using NSObject Class in swift. This variables is according to my requirement. you can modify for your requirement.

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

This is for a same data type.

{ $0.user_id == cliectScreenSelectedObject.user_id }

If you want to AnyObject type.

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

Full condition

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

    cliectScreenSelected.append(cliectScreenSelectedObject)

    print("Object Added")

} else {

    print("Object already exists")

 }

J
James Rochabrun

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

k
koen

Swift 4.2 + You can easily verify your instance is an array or not by the following function.

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

   return false
}

Even you can access it as follows. You will receive nil if the object wouldn't be an array.

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

   return nil
}

K
Kevin Waltz

You can add an extension for Array as such:

extension Array {
     func contains<T>(_ object: T) -> Bool where T: Equatable {
         !self.filter {$0 as? T == object }.isEmpty
     }
 }

This can be used as:

if myArray.contains(myItem) {
   // code here
}