Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

check if all elements of an array have the same value in Swift

Tags:

arrays

swift

Is there a function in Swift that checks whether all elements of an array have the same value? In my case, it's an array of type Int. I know I can iterate over it using a simple for loop I was just wondering if there is something that is built in and quicker.

like image 325
nevos Avatar asked Apr 12 '15 09:04

nevos


People also ask

How do you check if all values in an array are the same?

To check if all values in an array are equal:Use the Array. every() method to iterate over the array. Check if each array element is equal to the first one. The every method only returns true if the condition is met for all array elements.

How do you check if an array contains a value Swift?

It's easy to find out whether an array contains a specific value, because Swift has a contains() method that returns true or false depending on whether that item is found. For example: let array = ["Apples", "Peaches", "Plums"] if array.

How do I compare two array elements in Swift?

To check if two arrays are equal in Swift, use Equal To == operator. Equal To operator returns a Boolean value indicating whether two arrays contain the same elements in the same order. If two arrays are equal, then the operator returns true , or else it returns false .

How do I filter an array in Swift?

To filter an array in Swift: Call the Array. filter() method on an array. Pass a filtering function as an argument to the method.


2 Answers

With Swift 5, you can use one of the four following ways in order to tests if all elements of an array are equal.


#1. Using Array's allSatisfy(_:) method

allSatisfy(_:) returns a Boolean value indicating whether every element of a sequence satisfies a given predicate. You can set the predicate to test if all elements of the array are equal:

let array = [1, 1, 1]  let hasAllItemsEqual = array.dropFirst().allSatisfy({ $0 == array.first }) print(hasAllItemsEqual) // prints: true 
let array = [1, 1, 3]  let hasAllItemsEqual = array.dropFirst().allSatisfy({ $0 == array.first }) print(hasAllItemsEqual) // prints: false 
let array = [Int]()  let hasAllItemsEqual = array.dropFirst().allSatisfy({ $0 == array.first }) print(hasAllItemsEqual) // prints: true 

#2. Using Array's reduce(_:_:) method

As an alternative to allSatisfy(_:), you can use reduce(_:_:):

let array = [1, 1, 1]  let hasAllItemsEqual = array.dropFirst().reduce(true) { (partialResult, element) in     return partialResult && element == array.first } print(hasAllItemsEqual) // prints: true 
let array = [1, 1, 3]  let hasAllItemsEqual = array.dropFirst().reduce(true) { (partialResult, element) in     return partialResult && element == array.first } print(hasAllItemsEqual) // prints: false 
let array = [Int]()  let hasAllItemsEqual = array.dropFirst().reduce(true) { (partialResult, element) in     return partialResult && element == array.first } print(hasAllItemsEqual) // prints: true 

#3. Using elementsEqual(_:) method

elementsEqual(_:) returns a Boolean value indicating whether two sequences contain the same elements in the same order. Therefore you can create a new collection by repeating the first element of the initial array and compare the former with the latter:

let array = [1, 1, 1]  precondition(!array.isEmpty) let repeated = repeatElement(array[0], count: array.count)  let hasAllItemsEqual = array.elementsEqual(repeated) print(hasAllItemsEqual) // prints: true 
let array = [1, 1, 3]  precondition(!array.isEmpty) let repeated = repeatElement(array[0], count: array.count)  let hasAllItemsEqual = array.elementsEqual(repeated) print(hasAllItemsEqual) // prints: false 

#4. Using Set's init(_:) initalizer

If all elements of an array are equal, creating a set from this array should result in the set having only one element:

let array = [1, 1, 1]  let set = Set(array) let hasAllItemsEqual = set.count <= 1 print(hasAllItemsEqual) // prints: true 
let array = [1, 1, 3]  let set = Set(array) let hasAllItemsEqual = set.count <= 1 print(hasAllItemsEqual) // prints: false 
let array = [Int]()  let set = Set(array) let hasAllItemsEqual = set.count <= 1 print(hasAllItemsEqual) // prints: true 
like image 192
Imanou Petit Avatar answered Sep 23 '22 15:09

Imanou Petit


Any method must iterate over all elements until a different element is found:

func allEqualUsingLoop<T : Equatable>(array : [T]) -> Bool {     if let firstElem = array.first {         for elem in array {             if elem != firstElem {                 return false             }         }     }     return true } 

Instead of an explicit loop you can use the contains() function:

func allEqualUsingContains<T : Equatable>(array : [T]) -> Bool {     if let firstElem = array.first {         return !contains(array, { $0 != firstElem })     }     return true } 

If the array elements are Hashable (such as Int) then you can create a Set (available since Swift 1.2) from the array elements and check if it has exactly one element.

func allEqualUsingSet<T : Hashable>(array : [T]) -> Bool {     let uniqueElements = Set(array)     return count(uniqueElements) <= 1 } 

A quick benchmarking test revealed that the "contains" method is much faster than the "set" method for an array of 1,000,000 integers, in particular if the elements are not all equal. This make sense because contains() returns as soon as a non-matching element is found, whereas Set(array) always traverses the entire array.

Also the "contains" methods is equally fast or slightly faster than an explicit loop.

Here is some simple benchmarking code. Of course the results can vary with the array size, the number of different elements and the elements data type.

func measureExecutionTime<T>(title: String,  @noescape f : (() -> T) ) -> T {     let start = NSDate()     let result = f()     let end = NSDate()     let duration = end.timeIntervalSinceDate(start)     println("\(title) \(duration)")     return result }  var array = [Int](count: 1_000_000, repeatedValue: 1) array[500_000] = 2  let b1 = measureExecutionTime("using loop    ") {     return allEqualUsingLoop(array) }  let b2 = measureExecutionTime("using contains") {     allEqualUsingContains(array) }  let b3 = measureExecutionTime("using set     ") {     allEqualUsingSet(array) } 

Results (on a MacBook Pro, Release configuration):

 using loop     0.000651001930236816 using contains 0.000567018985748291 using set      0.0344770550727844 

With array[1_000] = 2 the results are

 using loop     9.00030136108398e-06 using contains 2.02655792236328e-06 using set      0.0306439995765686 

Update for Swift 2/Xcode 7: Due to various changes in the Swift syntax, the function is now written as

func allEqual<T : Equatable>(array : [T]) -> Bool {     if let firstElem = array.first {         return !array.dropFirst().contains { $0 != firstElem }     }     return true } 

But you can now also define it as an extension method for arrays:

extension Array where Element : Equatable {     func allEqual() -> Bool {         if let firstElem = first {             return !dropFirst().contains { $0 != firstElem }         }         return true     } }  print([1, 1, 1].allEqual()) // true print([1, 2, 1].allEqual()) // false 
like image 36
Martin R Avatar answered Sep 23 '22 15:09

Martin R