Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Swift: Efficient way to convert a dictionary into another dictionary where all the keys are modified?

In Swift, I have this type of dictionary:

let typingAttributes = [NSAttributedString.Key.font:UIFont.systemFont(ofSize: 18),NSAttributedString.Key.foregroundColor:UIColor.red]

I need to convert it into another dictionary where the key is the "rawValue". So something like this:

[NSAttributedString.Key.font.rawValue:UIFont.systemFont(ofSize: 18),NSAttributedString.Key.foregroundColor.rawValue:UIColor.red]

One way I know I can achieve this is by creating a new dictionary, then enumerating all the keys of the original dictionary and setting the values in this new dictionary.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

However, is there a better way similar to how Arrays have things like map, reduce etc?

>Solution :

A solution is to use reduce(into:_:):

let output = typingAttributes.reduce(into: [String: Any]()) { partialResult, tuple in
    let newKey = //Get new key from tuple.key
    partialResult[newKey] = tuple.value
}

In your case, since you are using NSAttributedString.Key for the dictionary keys, and you want the raw string value:

let newKey = tuple.key.rawValue

Which can then be simplified into:

let output = typingAttributes.reduce(into: [String: Any]()) { 
    $0[$1.key.rawValue] = $1.value
}

With an extension:

extension Dictionary {
    func mapKeys<T>(_ key: (Key) -> T) -> [T: Value] {
        reduce(into: [T: Value]()) {
            let newKey = key($1.key)
            $0[newKey] = $1.value
        }
    }
}

Usages:

let output = typingAttributes.mapKeys { $0.rawValue }

Other samples uses:

//Convert the keys into their int value (it'd crash if it's not an int)
let testInt = ["1": "a", "2": "b"].mapKeys { Int($0)! }
print(testInt)


//Keep only the first character of the keys
let testPrefix = ["123": "a", "234": "b"].mapKeys { String($0.prefix(1)) }
print(testPrefix)

//Fixing keys into our owns, more "readable" and "Swift friendly for instance
let keysToUpdate = ["lat": "latitude", "long": "longitude", "full_name": "fullName"]
let testFixKeys = ["lat": 0.4, "long": 0.5, "full_name": "Seed", "name": "John", "age": 34].mapKeys { keysToUpdate[$0] ?? $0 }
print(testFixKeys)

//etc.
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading