Contains in Swift

While coding Swift, we use contains(element:) to determine if an array contains the element or not. For example:

enum Animal {
case dog
case cat
}
let animals: [Animal] = [.dog, .dog]
let hasCat = animals.contains(.cat) // false

Looks pretty simple, right? However, let us change Animal enum’s definition with associated values like this:

enum Animal {
case dog(String)
case cat(String)
}
let animals: [Animal] = [.dog("Growlithe"), .dog("Rockruff")]
let hasCat = animals.contains(.cat("Meowth")) // compile error

Boo, compile error! This is due to the element used in contains(element:) function should conform to Equatable protocol, while Animal enum with associated value does not.

Fortunately, we have another contains function defined as below:

public func contains(where predicate: (Element) throws -> Bool) rethrows -> Bool

This function takes a closure as a parameter — the predicate. We could use it to define how to check an element of a type that doesn’t conform to the Equatable protocol.

Based on this contains function, let us fix the compile error above:

enum Animal {
  case dog(String)
  case cat(String)
}

let animals: [Animal] = [.dog("Growlithe"), .dog("Rockruff")]
let hasCat = animals.contains { animal in
  if case .cat = animal {
    return true
  }
  return false
}

Now hasCat would return false. Alternatively, a predicate can be satisfied by a range of Equatable elements or a general condition. This example shows how you can check an array for an element could be divided by 7.

let array = [2, 5, 6, 7, 19, 40]

array.contains { (element) -> Bool in
element % 7 == 0
}

Apple’s API page also offers a very good example in handling network response with contains(where:) function.

If you have a better use case, please share it in the comments below!