From a0f2111a510c9137db05e208b8d0a4044bd5fd70 Mon Sep 17 00:00:00 2001 From: Kyle Matthew Hedden Date: Fri, 22 Jul 2022 15:52:17 -0400 Subject: [PATCH] add additional dictionary convenience functions for transformations --- .../Categories/Dictionary+MFConvenience.swift | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/MVMCore/MVMCore/Categories/Dictionary+MFConvenience.swift b/MVMCore/MVMCore/Categories/Dictionary+MFConvenience.swift index 8e11396..efef7d3 100644 --- a/MVMCore/MVMCore/Categories/Dictionary+MFConvenience.swift +++ b/MVMCore/MVMCore/Categories/Dictionary+MFConvenience.swift @@ -192,6 +192,61 @@ public extension Dictionary { return previousObject } + + /// Transforms dictionary keys without modifying values. + /// Deduplicates transformed keys. + /// + /// Example: + /// ``` + /// ["one": 1, "two": 2, "three": 3, "": 4].mapKeys({ $0.first }, uniquingKeysWith: { max($0, $1) }) + /// // [Optional("o"): 1, Optional("t"): 3, nil: 4] + /// ``` + /// + /// - Parameters: + /// - transform: A closure that accepts each key of the dictionary as + /// its parameter and returns a transformed key of the same or of a different type. + /// - combine:A closure that is called with the values for any duplicate + /// keys that are encountered. The closure returns the desired value for + /// the final dictionary. + /// - Returns: A dictionary containing the transformed keys and values of this dictionary. + func mapKeys(_ transform: (Key) throws -> T, uniquingKeysWith combine: (Value, Value) throws -> Value) rethrows -> [T: Value] { + try .init(map { (try transform($0.key), $0.value) }, uniquingKeysWith: combine) + } + + /// Transforms dictionary keys without modifying values. + /// Drops (key, value) pairs where the transform results in a nil key. + /// Deduplicates transformed keys. + /// + /// Example: + /// ``` + /// ["one": 1, "two": 2, "three": 3, "": 4].compactMapKeys({ $0.first }, uniquingKeysWith: { max($0, $1) }) + /// // ["o": 1, "t": 3] + /// ``` + /// + /// - Parameters: + /// - transform: A closure that accepts each key of the dictionary as + /// its parameter and returns an optional transformed key of the same or of a different type. + /// - combine: A closure that is called with the values for any duplicate + /// keys that are encountered. The closure returns the desired value for + /// the final dictionary. + /// - Returns: A dictionary containing the non-nil transformed keys and values of this dictionary. + func compactMapKeys(_ transform: (Key) throws -> T?, uniquingKeysWith combine: (Value, Value) throws -> Value) rethrows -> [T: Value] { + try .init(compactMap { (try transform($0.key), $0.value) as? (T, Value) }, uniquingKeysWith: combine) + } + + /// Unconditionally merge another dictionary into this one with preference to the incoming keys. + func mergingLeft(_ other: Self) -> Self { + return merging(other) { first, second in + second + } + } + + /// Unconditionally merge this dictionary into another with preference to the existing keys. + func mergingRight(_ other: Self) -> Self { + return merging(other) { first, second in + first + } + } } public extension Optional where Wrapped == Dictionary {