Domanda Come faccio a confrontare due dizionari in Swift?


C'è un modo semplice per confrontare due [String: AnyObject] dizionari in rapido, dal momento che non accetta il == operatore?

Confrontando due dizionari, intendo controllare che abbiano le stesse chiavi esatte e che per ogni chiave abbiano gli stessi valori.


44
2017-09-03 01:31


origine


risposte:


Come già menzionato da Hot Licks puoi usare il metodo NSDictionary isEqualToDictionary() per verificare se sono uguali come segue:

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

puoi anche implementare un operatore personalizzato "==" come segue:

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

Da docs, il dizionario è ora definito come una struttura:

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

Descrizione

Una collezione i cui elementi sono coppie chiave-valore. UN   dizionario è un tipo di tabella hash, che fornisce un accesso veloce al   voci che contiene. Ogni voce nella tabella viene identificata utilizzando la sua   chiave, che è un tipo lavabile come una stringa o un numero. Lo usi   chiave per recuperare il valore corrispondente, che può essere qualsiasi oggetto. In   altre lingue, tipi di dati simili sono noti come hash o associati   array. Crea un nuovo dizionario usando un dizionario letterale. UN   dizionario letterale è un elenco separato da virgole di coppie chiave-valore, in   che un colon separa ogni chiave dal suo valore associato, circondato   da parentesi quadre. È possibile assegnare un dizionario letterale a una variabile   o costante o passarlo a una funzione che si aspetta un dizionario.

Ecco come crei un dizionario di codici di risposta HTTP e i relativi messaggi:

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

La variabile responseMessages viene dedotta per avere il tipo [Int: String].   Il tipo di chiave del dizionario è Inte il tipo di valore del   il dizionario è String.

Per creare un dizionario senza coppie di valori-chiave, utilizzare un dizionario vuoto letterale ([:]).

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

Qualsiasi tipo conforme al protocollo Hashable può essere utilizzato come tipo di chiave del dizionario, inclusi tutti i tipi di base di Swift. Puoi utilizzare i tuoi tipi personalizzati come chiavi del dizionario rendendoli conformi al protocollo Hashable.


Non è più necessario definire un operatore personalizzato:

Dai documenti:

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

test:

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

Nell'esempio sopra riportato, tutte le chiavi e i valori del dizionario sono dello stesso tipo. Se proviamo a confrontare due dizionari di tipo [String: Any] Xcode si lamenterà che l'operatore binario == non può essere applicato a due [String: Any] operandi.

    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

Ma possiamo estendere il == funzionalità dell'operatore che implementa un operatore infisso, che converte Swift Dictionary in NSDictionary e che limita il protocollo Dictionary to Hashable Protocol:


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

test:

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

78
2017-09-03 04:22



In Swift 2, quando entrambi Key e Value siamo Equatable, Puoi usare == sul dizionario stesso:

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

E, NSObject è equo:

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

Nel tuo caso, se stai lavorando con oggetti Obj-C che vuoi confrontare usando isEqual:, puoi semplicemente usare NSObject come tipo di valore (piuttosto che AnyObject).


11
2017-09-03 01:59



Aggiornamento Swift 4:

Il confronto dei dizionari ora è nativo! (Documenti Qui)


Swift 3:

Leo Dabus ha già un post scritto in modo eccellente con la soluzione accettata. Tuttavia, per quanto mi riguarda, ho scoperto che era necessario un ulteriore passo per essere pienamente utilizzabile. Come puoi vedere dal suo codice, devi impostare il tuo tipo di dizionario su [AnyHashable: Any]o altrimenti otterrai Binary operator '==' cannot be applied to two '[String : Any]' operands, per usare un dizionario comune nella deserializzazione del JSON per il mio esempio.

Generici in soccorso !:

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

o in un altro caso ho avuto, con [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)
}

11
2018-02-27 18:55



Senza il tipo personalizzato di valore del dizionario, in Swift 2+ puoi usare il == operatore per confrontare due Dictionary per verificare se sono uguali o meno.

Ma in alcuni casi con tipi personalizzati come il Dictionaryvalore (come struct), è necessario adottare Equatable per poter utilizzare quel tipo personalizzato == operatore.

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

Ora puoi usare il == operatore per confrontare due dizionari:

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

1
2017-08-05 03:16