EZSwiftExtensions/Sources/DictionaryExtensions.swift

183 lines
6.1 KiB
Swift

//
// DictionaryExtensions.swift
// EZSwiftExtensions
//
// Created by Goktug Yilmaz on 15/07/15.
// Copyright (c) 2015 Goktug Yilmaz. All rights reserved.
//
import Foundation
extension Dictionary {
/// EZSE: Returns the value of a random Key-Value pair from the Dictionary
public func random() -> Value? {
return Array(values).random()
}
/// EZSE: Union of self and the input dictionaries.
public func union(_ dictionaries: Dictionary...) -> Dictionary {
var result = self
dictionaries.forEach { (dictionary) -> Void in
dictionary.forEach { (key, value) -> Void in
result[key] = value
}
}
return result
}
/// EZSE: Intersection of self and the input dictionaries.
/// Two dictionaries are considered equal if they contain the same [key: value] copules.
public func intersection<K, V: Equatable>(_ dictionaries: [K: V]...) -> [K: V] {
// Casts self from [Key: Value] to [K: V]
let filtered = mapFilter { (item, value) -> (K, V)? in
if let item = item as? K, let value = value as? V {
return (item, value)
}
return nil
}
// Intersection
return filtered.filter { (arg: (key: K, value: V)) -> Bool in
// check for [key: value] in all the dictionaries
let (key, value) = arg
return dictionaries.testAll { $0.has(key) && $0[key] == value }
}
}
/// EZSE: Checks if a key exists in the dictionary.
public func has(_ key: Key) -> Bool {
return index(forKey: key) != nil
}
/// EZSE: Creates an Array with values generated by running
/// each [key: value] of self through the mapFunction.
public func toArray<V>(_ map: (Key, Value) -> V) -> [V] {
return self.map(map)
}
/// EZSE: Creates a Dictionary with the same keys as self and values generated by running
/// each [key: value] of self through the mapFunction.
public func mapValues<V>(_ map: (Key, Value) -> V) -> [Key: V] {
var mapped: [Key: V] = [:]
forEach {
mapped[$0] = map($0, $1)
}
return mapped
}
/// EZSE: Creates a Dictionary with the same keys as self and values generated by running
/// each [key: value] of self through the mapFunction discarding nil return values.
public func mapFilterValues<V>(_ map: (Key, Value) -> V?) -> [Key: V] {
var mapped: [Key: V] = [:]
forEach {
if let value = map($0, $1) {
mapped[$0] = value
}
}
return mapped
}
/// EZSE: Creates a Dictionary with keys and values generated by running
/// each [key: value] of self through the mapFunction discarding nil return values.
public func mapFilter<K, V>(_ map: (Key, Value) -> (K, V)?) -> [K: V] {
var mapped: [K: V] = [:]
forEach {
if let value = map($0, $1) {
mapped[value.0] = value.1
}
}
return mapped
}
/// EZSE: Creates a Dictionary with keys and values generated by running
/// each [key: value] of self through the mapFunction.
public func map<K, V>(_ map: (Key, Value) -> (K, V)) -> [K: V] {
var mapped: [K: V] = [:]
forEach {
let (_key, _value) = map($0, $1)
mapped[_key] = _value
}
return mapped
}
/// EZSE: Constructs a dictionary containing every [key: value] pair from self
/// for which testFunction evaluates to true.
public func filter(_ test: (Key, Value) -> Bool) -> Dictionary {
var result = Dictionary()
for (key, value) in self {
if test(key, value) {
result[key] = value
}
}
return result
}
/// EZSE: Checks if test evaluates true for all the elements in self.
public func testAll(_ test: (Key, Value) -> (Bool)) -> Bool {
return !contains { !test($0, $1) }
}
/// EZSE: Unserialize JSON string into Dictionary
public static func constructFromJSON (json: String) -> Dictionary? {
if let data = (try? JSONSerialization.jsonObject(
with: json.data(using: String.Encoding.utf8,
allowLossyConversion: true)!,
options: JSONSerialization.ReadingOptions.mutableContainers)) as? Dictionary {
return data
} else {
return nil
}
}
/// EZSE: Serialize Dictionary into JSON string
public func formatJSON() -> String? {
if let jsonData = try? JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions()) {
let jsonStr = String(data: jsonData, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
return String(jsonStr ?? "")
}
return nil
}
}
extension Dictionary where Value: Equatable {
/// EZSE: Difference of self and the input dictionaries.
/// Two dictionaries are considered equal if they contain the same [key: value] pairs.
public func difference(_ dictionaries: [Key: Value]...) -> [Key: Value] {
var result = self
for dictionary in dictionaries {
for (key, value) in dictionary {
if result.has(key) && result[key] == value {
result.removeValue(forKey: key)
}
}
}
return result
}
}
/// EZSE: Combines the first dictionary with the second and returns single dictionary
public func += <KeyType, ValueType> (left: inout [KeyType: ValueType], right: [KeyType: ValueType]) {
for (k, v) in right {
left.updateValue(v, forKey: k)
}
}
/// EZSE: Difference operator
public func - <K, V: Equatable> (first: [K: V], second: [K: V]) -> [K: V] {
return first.difference(second)
}
/// EZSE: Intersection operator
public func & <K, V: Equatable> (first: [K: V], second: [K: V]) -> [K: V] {
return first.intersection(second)
}
/// EZSE: Union operator
public func | <K, V> (first: [K: V], second: [K: V]) -> [K: V] {
return first.union(second)
}