Как уже объяснялось в других ответах, тип Value
должен быть ограничен до Hashable
, в противном случае он не может быть Key
для нового словаря.
Также необходимо решитькак должны обрабатываться повторяющиеся значения в исходном словаре.
Для реализации можно сопоставить исходный словарь с последовательностью с обмененными ключами и значениями и передать ее одному из инициализаторов
Они отличаются в том, как обрабатываются дубликаты ключей: первый прерываетсяза исключением времени выполнения, второе вызывает закрытие для разрешения конфликта.
Таким образом, простая реализация -
extension Dictionary where Value: Hashable {
func swapKeyValues() -> [Value : Key] {
return Dictionary<Value, Key>(uniqueKeysWithValues: lazy.map { ($0.value, $0.key) })
}
}
(отображение исходного словаря lazily позволяет избежать созданияпромежуточного массива со всеми заменяемыми наборами ключ / значение.)
Пример:
let dict = [1 : "a", 2 : "b", 3 : "c", 4 : "d", 5 : "e"]
print(dict.swapKeyValues()) //["b": 2, "e": 5, "a": 1, "d": 4, "c": 3]
Это произойдет сбой, если исходный словарь имеет повторяющиеся значения.Вот вариант, который принимает повторяющиеся значения в исходном словаре (и «более поздние» значения перезаписывают «более ранние»):
extension Dictionary where Value: Hashable {
func swapKeyValues() -> [Value : Key] {
return Dictionary<Value, Key>(lazy.map { ($0.value, $0.key) }, uniquingKeysWith: { $1 })
}
}
Пример:
let dict = [1 : "a", 2 : "b", 3 : "b"]
print(dict.swapKeyValues()) // ["b": 3, "a": 1]
Другой вариант - реализовать это как инициализатор словаря.Например:
extension Dictionary where Value: Hashable {
init?(swappingKeysAndValues dict: [Value: Key]) {
self.init(uniqueKeysWithValues: dict.lazy.map( { ($0.value, $0.key) }))
}
}
, который дает сбой в случае дублирования значений в исходном словаре или в качестве бросающего инициализатора
extension Dictionary where Value: Hashable {
struct DuplicateValuesError: Error, LocalizedError {
var errorDescription: String? {
return "duplicate value"
}
}
init(swappingKeysAndValues dict: [Value: Key]) throws {
try self.init(dict.lazy.map { ($0.value, $0.key) },
uniquingKeysWith: { _,_ in throw DuplicateValuesError() })
}
}
или в качестве сбойного инициализатора:
extension Dictionary where Value: Hashable {
struct DuplicateValuesError: Error { }
init?(swappingKeysAndValues dict: [Value: Key]) {
do {
try self.init(dict.lazy.map { ($0.value, $0.key) },
uniquingKeysWith: { _,_ in throw DuplicateValuesError() })
} catch {
return nil
}
}
}
Пример (для сбойного инициализатора):
let dict = [1 : "a", 2 : "b", 3 : "c", 4 : "d", 5 : "e"]
if let newDict = Dictionary(swappingKeysAndValues: dict) {
print(newDict) //["b": 2, "e": 5, "a": 1, "d": 4, "c": 3]
}
Или, если вы уверены, что повторяющиеся значения не встречаются:
let dict = [1 : "a", 2 : "b", 3 : "c", 4 : "d", 5 : "e"]
let newDict = Dictionary(swappingKeysAndValues: dict)!