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

nev*_*vos 19 arrays swift

Swift中是否有一个函数检查数组的所有元素是否具有相同的值?就我而言,它是一个类型的数组Int.我知道我可以使用一个简单的for循环迭代它我只是想知道是否有内置和更快的东西.

Mar*_*n R 33

任何方法都必须迭代所有元素,直到找到不同的元素:

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

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

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

如果数组元素是Hashable(例如Int)那么你可以Set从数组元素创建一个(从Swift 1.2开始可用)并检查它是否只有一个元素.

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

快速基准测试显示,对于1,000,000个整数的数组,"contains"方法比"set"方法快得多,特别是如果元素 并非全部相等.这是有道理的,因为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)
}
Run Code Online (Sandbox Code Playgroud)

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

using loop     0.000651001930236816
using contains 0.000567018985748291
using set      0.0344770550727844

随着array[1_000] = 2结果

using loop     9.00030136108398e-06
using contains 2.02655792236328e-06
using set      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
}
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)


Rom*_*mov 11

Swift 4.2/Xcode 10的解决方案:

let arr = [1, 1, 1, 1]
let allItemsEqual = arr.dropLast().allSatisfy { $0 == arr.last }
print(allItemsEqual)
Run Code Online (Sandbox Code Playgroud)

如果您当前的Xcode的版本早于10.0,你可以找到函数allSatisfyArraySliceXcode9to10Preparation.您可以使用CocoaPods安装此库.

  • 我知道检查最后一个对象是否等于自身是多余的,但是遍历数组 3 次或 4 次在 CS 术语中具有相同的复杂性,所以这并不重要。 (2认同)

Ima*_*tit 6

使用Swift 5,您可以使用以下四种方法之一来测试数组的所有元素是否相等。


#1 使用ArrayallSatisfy(_:)方法

allSatisfy(_:)返回一个布尔值,该值指示序列中的每个元素是否满足给定谓词。您可以设置谓词以测试数组的所有元素是否相等:

let array = [1, 1, 1]

let hasAllItemsEqual = array.dropFirst().allSatisfy({ $0 == array.first })
print(hasAllItemsEqual) // prints: true
Run Code Online (Sandbox Code Playgroud)
let array = [1, 1, 3]

let hasAllItemsEqual = array.dropFirst().allSatisfy({ $0 == array.first })
print(hasAllItemsEqual) // prints: false
Run Code Online (Sandbox Code Playgroud)
let array = [Int]()

let hasAllItemsEqual = array.dropFirst().allSatisfy({ $0 == array.first })
print(hasAllItemsEqual) // prints: true
Run Code Online (Sandbox Code Playgroud)

#2。使用Arrayreduce(_:_:)方法

作为替代allSatisfy(_:),您可以使用reduce(_:_:)

let array = [1, 1, 1]

let hasAllItemsEqual = array.dropFirst().reduce(true) { (partialResult, element) in
    return partialResult && element == array.first
}
print(hasAllItemsEqual) // prints: true
Run Code Online (Sandbox Code Playgroud)
let array = [1, 1, 3]

let hasAllItemsEqual = array.dropFirst().reduce(true) { (partialResult, element) in
    return partialResult && element == array.first
}
print(hasAllItemsEqual) // prints: false
Run Code Online (Sandbox Code Playgroud)
let array = [Int]()

let hasAllItemsEqual = array.dropFirst().reduce(true) { (partialResult, element) in
    return partialResult && element == array.first
}
print(hasAllItemsEqual) // prints: true
Run Code Online (Sandbox Code Playgroud)

#3。使用elementsEqual(_:)方法

elementsEqual(_:)返回一个布尔值,该值指示两个序列是否包含相同顺序的相同元素。因此,您可以通过重复初始数组的第一个元素并将其与后者进行比较来创建新集合:

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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

#4。使用Setinit(_:)初始化器

如果数组的所有元素均相等,则从该数组创建一个集合应导致该集合中只有一个元素:

let array = [1, 1, 1]

let set = Set(array)
let hasAllItemsEqual = set.count <= 1
print(hasAllItemsEqual) // prints: true
Run Code Online (Sandbox Code Playgroud)
let array = [1, 1, 3]

let set = Set(array)
let hasAllItemsEqual = set.count <= 1
print(hasAllItemsEqual) // prints: false
Run Code Online (Sandbox Code Playgroud)
let array = [Int]()

let set = Set(array)
let hasAllItemsEqual = set.count <= 1
print(hasAllItemsEqual) // prints: true
Run Code Online (Sandbox Code Playgroud)