Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
592 views
in Technique[技术] by (71.8m points)

check if all elements of an array have the same value in 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...