小编典典

检查数组的所有元素在Swift中是否具有相同的值

swift

Swift中是否有一个函数可以检查数组的所有元素是否具有相同的值?就我而言,它是一个type数组Int。我知道我可以使用一个简单的for循环对其进行迭代,我只是想知道是否内置了某些东西并且速度更快。


阅读 729

收藏
2020-07-07

共1个答案

小编典典

任何方法都必须遍历所有元素,直到找到另一个元素:

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

可以使用以下contains()函数来代替显式循环:

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

如果数组元素是Hashable(例如Int),则可以Set从数组元素创建一个(从Swift 1.2开始可用),并检查它是否恰好具有一个元素。

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

快速基准测试显示,对于包含1,000,000个整数的数组,“包含”方法比“设置”方法快得多,尤其是在元素
完全相等的情况下。这是有道理的,因为contains()一旦找到不匹配的元素就返回,而Set(array)总是遍历整个数组。

同样,“包含”方法比显式循环同样快或稍快。

这是一些简单的基准测试代码。当然,结果可能会随数组大小,不同元素的数量和元素数据类型而变化。

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

结果(在MacBook Pro上,发布配置):

使用循环0.000651001930236816
使用包含0.000567018985748291
使用设置0.0344770550727844

随着array[1_000] = 2结果

使用循环9.00030136108398e-06
使用包含2.02655792236328e-06
使用设置0.0306439995765686

Swift 2 / Xcode 7更新: 由于Swift语法的各种变化,该函数现在编写为

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

但是您现在也可以将其定义为数组的扩展方法:

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
2020-07-07