564

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
}
Emil Laine
  • 41,598
  • 9
  • 101
  • 157
jaredsmith
  • 7,306
  • 3
  • 20
  • 31

18 Answers18

991

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:

Swift older versions:

let elements = [1,2,3,4,5]
if contains(elements, 5) {
    println("yes")
}
Sazzad Hissain Khan
  • 37,929
  • 33
  • 189
  • 256
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • 4
    Any documentation about this kind of global functions? – Rivera Apr 13 '15 at 21:25
  • 3
    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 Apr 29 '15 at 21:18
  • 8
    @ppalancica: This requires that the array elements conform to the `Equatable` protocol (which `Dictionary` doesn't). There is a second variant of `contains()` which takes a predicate (compare http://stackoverflow.com/questions/29679486/shorthand-to-test-if-an-object-exists-in-an-array-for-swift) perhaps you can use that, e.g. `if contains(array, { $0 == dict } ) ...` – Martin R Apr 29 '15 at 21:25
  • How to search specific element from generic array? say [AnyObject] ? – Dhaval H. Nena Jul 07 '16 at 06:27
155

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)
}
Joannes
  • 2,569
  • 3
  • 17
  • 39
DogCoffee
  • 19,820
  • 10
  • 87
  • 120
70

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)
David Berry
  • 40,941
  • 12
  • 84
  • 95
  • 1
    depending on what you're used to though, .contains may feel more intuitive and memorable – Pirijan Jul 26 '14 at 22:34
  • 4
    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! – Aggressor Dec 26 '14 at 19:18
  • I changed the original code to use .isEmpty as it is a practice suggested by SwiftLint. – Douglas Frari Jan 05 '22 at 14:34
  • Don't use this extension, it's horrible. Just use https://developer.apple.com/documentation/swift/array/2945493-contains – NoKey Feb 05 '22 at 17:51
  • 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. – David Berry Feb 09 '22 at 02:37
46

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

andrewtweber
  • 24,520
  • 22
  • 88
  • 110
Andrew Schreiber
  • 14,344
  • 6
  • 46
  • 53
  • 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. – Kevin Apr 19 '22 at 09:36
32

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
}
Jeffery Thomas
  • 42,202
  • 8
  • 92
  • 117
  • 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. – Maury Markowitz Mar 08 '15 at 14:39
  • 1
    filter is inefficient because it always loops over all elements instead of returning immediately when the element is found. Better use find() instead. – Thorsten Apr 19 '15 at 16:44
25

(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).

Community
  • 1
  • 1
dfrib
  • 70,367
  • 12
  • 127
  • 192
  • How can I remove the firstSuchElement from the array? – i6x86 Feb 05 '17 at 23:59
  • @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). – dfrib Feb 06 '17 at 08:48
20

An array that contains a property that equals to

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

Returns boolean.

Honcharov Anton
  • 212
  • 2
  • 8
14

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
}
davetw12
  • 1,815
  • 2
  • 20
  • 27
  • 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 – Dan Beaulieu Oct 01 '15 at 20:33
  • 3
    @DanBeaulieu Doing something like `let result = elements.filter { $0==5 }.first` should accomplish what you're looking for. – davetw12 Oct 04 '15 at 16:03
  • @davetw12 No. This would unnecessarily iterate the whole collection. Better to use `first(where: predicate)`. – Leo Dabus Dec 14 '20 at 17:47
10

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")
}
Keshu R.
  • 5,045
  • 1
  • 18
  • 38
Pramod More
  • 1,220
  • 2
  • 22
  • 51
6

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

if myArray.containsObject(objectImCheckingFor){
    //myArray has the objectImCheckingFor
}
Chris Klingler
  • 5,258
  • 2
  • 37
  • 43
  • 4
    Actually that is for an NSArray. Not a swift array – Tycho Pandelaar Mar 15 '16 at 14:40
  • 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 } – Vitalii May 18 '16 at 10:26
6

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
Community
  • 1
  • 1
Sazzad Hissain Khan
  • 37,929
  • 33
  • 189
  • 256
3

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
        }
    }
Ali
  • 18,665
  • 21
  • 103
  • 138
2

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.

DevAndArtist
  • 4,971
  • 1
  • 23
  • 48
2

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")   }
Yogesh shelke
  • 438
  • 4
  • 12
2

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
}
kaevinio
  • 351
  • 1
  • 7
1

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

 }
Anit Kumar
  • 8,075
  • 1
  • 24
  • 27
1

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
James Rochabrun
  • 4,137
  • 2
  • 20
  • 17
1

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
}
koen
  • 5,383
  • 7
  • 50
  • 89
Kiran Jasvanee
  • 6,362
  • 1
  • 36
  • 52