web-dev-qa-db-fra.com

vérifie si tous les éléments d'un tableau ont la même valeur dans Swift

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.

13
nevos

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
28
Martin R

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.

7
Roman Podymov

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.


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

allSatisfy(_:) 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

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

Au 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

# 3. Utilisation de elementsEqual(_:) method

elementsEqual(_:) 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

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

Si 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
0
Imanou Petit