Подтвердить что ты не робот

Как сравнить два словаря в Swift?

Есть ли простой способ сравнить два словаря [String: AnyObject] в swift, так как он не принимает оператор ==?

Сравнивая два словаря, я имею в виду проверку того, что они имеют одинаковые точные ключи, и для каждого ключа они имеют одинаковые значения.

4b9b3361

Ответ 1

Как уже упоминалось Hot Licks, вы можете использовать метод NSDictionary isEqualToDictionary(), чтобы проверить, равны ли они следующим:

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

вы также можете реализовать пользовательский оператор "==" следующим образом:

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

В документах словарь теперь определяется как struct:

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

Описание

Коллекция, элементы которой являются парами ключ-значение. словарь - это тип хеш-таблицы, обеспечивающий быстрый доступ к содержащиеся в нем записи. Каждая запись в таблице идентифицируется с использованием ее ключ, который является хэширующим типом, таким как строка или номер. Вы используете это чтобы получить соответствующее значение, которое может быть любым объектом. В другие языки, аналогичные типы данных известны как хеши или связанные массивы. Создайте новый словарь, используя словарь. dictionary literal - это список пар ключ-значение, разделенный запятыми, в который двоеточие отделяет каждую клавишу от связанного с ней значения, окружено квадратными скобками. Вы можете назначить литерал словаря переменной или константу или передать ее функции, которая ожидает словарь.

Вот как вы создадите словарь кодов ответов HTTP и связанных с ними сообщений:

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

В переменной responseMessages указывается тип [Int: String]. Тип ключа словаря - Int, а тип значения словарь String.

Чтобы создать словарь без пар ключ-значение, используйте пустой литерал словаря ([:]).

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

Любой тип, который соответствует протоколу Hashable, может использоваться в качестве типа ключа словаря, включая все базовые типы Swift. Вы можете использовать свои собственные пользовательские типы в качестве ключей словаря, сделав их соответствующими протоколу Hashable.


Нам больше не нужно определять пользовательский оператор:

Из документов:

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

Тестирование:

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

В приведенном выше примере все словарные ключи и значения одного типа. Если мы попытаемся сравнить два словаря типа [String: Any], Xcode будет жаловаться на то, что двоичный оператор == не может быть применен к двум операндам [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

Но мы можем расширить функциональность оператора ==, внедряя инфиксный оператор, перебрасывая Swift Dictionary в NSDictionary и ограничивая значение словаря для значения Hashable Protocol:


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

Тестирование:

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

Ответ 2

В Swift 2, когда и Key и Value являются Equatable, вы можете использовать == в самом словаре:

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

И, NSObject равносилен:

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

В вашем случае, если вы работаете с объектами Obj-C, которые вы хотите сравнить с помощью isEqual:, вы можете просто использовать NSObject в качестве своего типа значения (а не для AnyObject).

Ответ 3

Лев Дабус уже имеет превосходное письменное сообщение с принятым решением. Тем не менее, для меня, я обнаружил, что для этого нужно еще один шаг, чтобы полностью использовать его. Как вы можете видеть из его кода, вам нужно установить тип словаря [AnyHashable: Any], иначе вы получите Binary operator '==' cannot be applied to two '[String : Any]' operands, чтобы использовать словарь, используемый при десериализации JSON для моего примера.

Общие для спасения!:

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

или в другом случае у меня было, с [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)
}

Ответ 4

Без специального типа в словарях в Swift 2+ вы можете использовать оператор == для сравнения двух Dictionary, чтобы проверить, равны они или нет.

Но в некоторых случаях с настраиваемыми типами как значение Dictionary (например, struct) вы должны принять Equatable, чтобы этот пользовательский тип использовал оператор ==.

Пример:

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

Теперь вы можете использовать оператор == для сравнения двух словарей:

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