web-dev-qa-db-fra.com

Comment comparer deux dictionnaires dans Swift?

Existe-t-il un moyen facile de comparer deux [String: AnyObject] dictionnaires dans Swift, car il n'accepte pas le == opérateur?

En comparant deux dictionnaires, je veux dire vérifier qu’ils ont exactement les mêmes clés et pour chaque clé, ils ont les mêmes valeurs.

61
bubakazouba

Comme mentionné par Hot Licks, vous pouvez utiliser la méthode NSDictionary isEqualToDictionary () pour vérifier si elles sont égales, comme suit:

let dic1: [String: AnyObject] = ["key1": 100, "key2": 200]
let dic2: [String: AnyObject] = ["key1": 100, "key2": 200]
let dic3: [String: AnyObject] = ["key1": 100, "key2": 250]

println( NSDictionary(dictionary: dic1).isEqualToDictionary(dic2) )   // true
println( NSDictionary(dictionary: dic1).isEqualToDictionary(dic3) )  // false

vous pouvez également implémenter un opérateur personnalisé "==" comme suit:

public func ==(lhs: [String: AnyObject], rhs: [String: AnyObject] ) -> Bool {
    return NSDictionary(dictionary: lhs).isEqualToDictionary(rhs)
}

println(dic1 == dic2)   // true
println(dic1 == dic3)   // false

Xcode 9 • Swift 4

A partir de la documentation, dictionnaire est maintenant défini comme une structure:

struct Dictionary<Key : Hashable, Value> : Collection, ExpressibleByDictionaryLiteral

La description

Une collection dont les éléments sont des paires clé-valeur. Un dictionnaire est un type de table de hachage, fournissant un accès rapide aux entrées qu'il contient. Chaque entrée de la table est identifiée à l'aide de sa clé, qui est un type pouvant être haché, tel qu'une chaîne ou un nombre. Vous utilisez cette clé pour extraire la valeur correspondante, qui peut être n’importe quel objet. Dans d'autres langages, des types de données similaires sont appelés hachages ou tableaux associés. Créez un nouveau dictionnaire en utilisant un littéral de dictionnaire. Un dictionnaire est une liste de paires clé-valeur séparées par des virgules, dans laquelle un point-virgule sépare chaque clé de sa valeur associée, entourée de crochets. Vous pouvez affecter un littéral de dictionnaire à une variable ou à une constante ou le transmettre à une fonction qui attend un dictionnaire.

Voici comment créer un dictionnaire des codes de réponse HTTP et des messages associés:

var responseMessages = [200: "OK",
                        403: "Access forbidden",
                        404: "File not found",
                        500: "Internal server error"]

La variable responseMessages est supposée avoir le type [Int: String]. Le type de clé du dictionnaire est Int et le type de valeur du dictionnaire est String.

Pour créer un dictionnaire sans paires clé-valeur, utilisez un littéral de dictionnaire vide ([:]).

var emptyDict: [String: String] = [:]

Tout type conforme au protocole Hashable peut être utilisé comme type de clé de dictionnaire, y compris tous les types de base de Swift. Vous pouvez utiliser vos propres types personnalisés comme clés de dictionnaire en les rendant conformes au protocole Hashable.


Nous n'avons plus besoin de définir un opérateur personnalisé:

De la docs:

static func ==(lhs: [Key : Value], rhs: [Key : Value]) -> Bool

Essai:

let dic1 = ["key1": 100, "key2": 200]
let dic2 = ["key1": 100, "key2": 200]
let dic3 = ["key1": 100, "key2": 250]

print(dic1 == dic2)   // true
print(dic1 == dic3)   // false

Dans l'exemple ci-dessus, les clés et les valeurs du dictionnaire sont du même type. Si nous essayons de comparer deux dictionnaires de type [String: Any], Xcode se plaindra que l’opérateur binaire == ne peut pas être appliqué à deux opérandes [String: Any].

    let dic4: [String: Any] = ["key1": 100, "key2": "200"]
    let dic5: [String: Any] = ["key1": 100, "key2": "200"]
    let dic6: [String: Any] = ["key1": 100, "key2": Date()]

    print(dic4 == dic5)  // Binary operator == cannot be applied to two `[String: Any]` operands

Mais nous pouvons étendre la fonctionnalité d’opérateur == En implémentant un opérateur infixe, en convertissant Swift Dictionary en NSDictionary et en contraignant la valeur du dictionnaire à Hashable Protocol:


public func ==<K, V: Hashable>(lhs: [K: V], rhs: [K: V] ) -> Bool {
    return (lhs as NSDictionary).isEqual(to: rhs)
}

Essai:

let dic4: [String: AnyHashable] = ["key1": 100, "key2": "200"]
let dic5: [String: AnyHashable] = ["key1": 100, "key2": "200"]
let dic6: [String: AnyHashable] = ["key1": 100, "key2": Date()]

print(dic4 == dic5)   // true
print(dic4 == dic6)   // false
96
Leo Dabus

Mise à jour de Swift 4:

La comparaison des dictionnaires est maintenant native! (Docs ici )


Swift 3:

Leo Dabus a déjà un poste très bien écrit avec la solution acceptée. Cependant, pour moi, j’ai trouvé qu’il fallait encore une étape pour être pleinement utilisable. Comme vous pouvez le constater à partir de son code, vous devez définir le type de dictionnaire sur [AnyHashable: Any], ou sinon vous aurez Binary operator '==' cannot be applied to two '[String : Any]' operands, pour utiliser un dictionnaire commun à la désérialisation de JSON pour mon exemple.

Les génériques à la rescousse !:

// Swift 3.0
func == <K, V>(left: [K:V], right: [K:V]) -> Bool {
    return NSDictionary(dictionary: left).isEqual(to: right)
}

ou dans un autre cas que j'ai eu avec [String: Any?]:

func == <K, V>(left: [K:V?], right: [K:V?]) -> Bool {
    guard let left = left as? [K: V], let right = right as? [K: V] else { return false }
    return NSDictionary(dictionary: left).isEqual(to: right)
}
13
AmitaiB

Dans Swift 2, lorsque Key et Value sont Equatable, vous pouvez utiliser == sur le dictionnaire lui-même:

public func ==<Key : Equatable, Value : Equatable>(lhs: [Key : Value], rhs: [Key : Value]) -> Bool

Et, NSObject est Equatable:

public func ==(lhs: NSObject, rhs: NSObject) -> Bool

Dans votre cas, si vous travaillez avec des objets Obj-C que vous voulez comparer avec isEqual:, vous pouvez simplement utiliser NSObject comme type de valeur (plutôt que AnyObject).

11
jtbandes

Sans valeur personnalisée dans Dictionary, dans Swift 2+, vous pouvez utiliser le == _ opérateur pour comparer deux Dictionary afin de vérifier s’ils sont égaux ou non.

Mais dans certains cas, avec des types personnalisés comme valeur de Dictionary (comme struct), vous devez adopter Equatable pour que ce type personnalisé utilise == _ opérateur.

Ex:

// custom type
struct Custom: Equatable {
    var value: Int
}

// MARK: adopting Equatable
func ==(lhs: Custom, rhs: Custom) -> Bool {
    if lhs.value == rhs.value {
        return true
    } else {
        return false
    }
}

Maintenant, vous pouvez utiliser le == opérateur pour comparer deux dictionnaires:

let dic3: [String: Custom] = ["key1": Custom(value:1), "key2": Custom(value:2)]
let dic4: [String: Custom] = ["key1": Custom(value:1), "key2": Custom(value:2)]

if (dic3 == dic4) {
    print("equal")
} else {
    print("not equal")
}
0
larva