Existe-t-il une fonction dans Swift qui vérifie si tous les éléments d’un tableau ont la même valeur? Dans mon cas, c'est un tableau de type Int
. Je sais que je peux le parcourir en utilisant une simple boucle for. Je me demandais simplement si quelque chose était intégré et plus rapide.
Toute méthode doit parcourir tous les éléments jusqu'à ce qu'un élément différent soit trouvé:
func allEqualUsingLoop<T : Equatable>(array : [T]) -> Bool {
if let firstElem = array.first {
for elem in array {
if elem != firstElem {
return false
}
}
}
return true
}
Au lieu d'une boucle explicite, vous pouvez utiliser la fonction contains()
:
func allEqualUsingContains<T : Equatable>(array : [T]) -> Bool {
if let firstElem = array.first {
return !contains(array, { $0 != firstElem })
}
return true
}
Si les éléments du tableau sont Hashable
(tels que Int
), vous pouvez créer un Set
(disponible depuis Swift 1.2) à partir des éléments du tableau et vérifier s'il contient exactement un élément.
func allEqualUsingSet<T : Hashable>(array : [T]) -> Bool {
let uniqueElements = Set(array)
return count(uniqueElements) <= 1
}
Un rapide test de comparaison a révélé que la méthode "contient" est beaucoup plus rapide que la méthode "set" pour un tableau de 1 000 000 entiers, en particulier si les éléments sont pas tous égaux. Cela a du sens, car contains()
retourne dès qu’un élément non correspondant est trouvé, alors que Set(array)
parcourt toujours l’ensemble du tableau.
De plus, les méthodes "contient" sont aussi rapides ou légèrement plus rapides qu'une boucle explicite.
Voici un code d'analyse comparative simple. Bien entendu, les résultats peuvent varier en fonction de la taille du tableau, du nombre d'éléments différents et du type de données des éléments.
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)
}
Résultats (sur un MacBook Pro, configuration Release):
en utilisant la boucle 0.000651001930236816 en utilisant contient 0,000567018985748291 en utilisant le jeu 0.0344770550727844
Avec array[1_000] = 2
les résultats sont
en utilisant la boucle 9.00030136108398e-06 en utilisant contient 2.02655792236328e-06 en utilisant le jeu 0.0306439995765686
Mise à jour pour Swift 2/Xcode 7: En raison de divers changements dans la syntaxe Swift, la fonction est maintenant écrite en tant que
func allEqual<T : Equatable>(array : [T]) -> Bool {
if let firstElem = array.first {
return !array.dropFirst().contains { $0 != firstElem }
}
return true
}
Mais vous pouvez maintenant aussi le définir comme méthode d’extension pour les tableaux:
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
Solution pour Swift 4.2/Xcode 10:
let arr = [1, 1, 1, 1]
let allItemsEqual = arr.dropLast().allSatisfy { $0 == arr.last }
print(allItemsEqual)
Si votre version actuelle de Xcode est antérieure à 10.0, vous pouvez trouver la fonction allSatisfy
de ArraySlice
dans Xcode9to10Preparation . Vous pouvez installer cette bibliothèque avec CocoaPods.
Avec Swift 5, vous pouvez utiliser l’une des quatre méthodes suivantes pour tester si tous les éléments d’un tableau sont égaux.
Array
's allSatisfy(_:)
methodallSatisfy(_:)
renvoie une valeur booléenne indiquant si chaque élément d'une séquence vérifie un prédicat donné. Vous pouvez configurer le prédicat pour tester si tous les éléments du tableau sont égaux:
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
Array
's reduce(_:_:)
methodAu lieu de allSatisfy(_:)
, vous pouvez utiliser 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
elementsEqual(_:)
methodelementsEqual(_:)
renvoie une valeur booléenne indiquant si deux séquences contiennent les mêmes éléments dans le même ordre. Par conséquent, vous pouvez créer une nouvelle collection en répétant le premier élément du tableau initial et comparer le premier avec le dernier:
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
Set
's init(_:)
initalizerSi tous les éléments d'un tableau sont égaux, la création d'un ensemble à partir de ce tableau devrait avoir pour résultat qu'un seul élément:
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