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 map nested dictionary to swap outer and inner keys

I’m building an app in swift which displays several graphs, one of which is a graph of exchange rates which can be filtered by currency code and date range within a UITableView. I’m able to successfully pull the FX data from https://fixer.io/ and convert that json data into the following swift struct:

struct FetchedFXRateByDate: Codable {
let success, timeseries: Bool
let startDate, endDate, base: String
let rates: [String: [String: Double]] // [Date: [Currency Code : Amount]]

enum CodingKeys: String, CodingKey {
    case success, timeseries
    case startDate = "start_date"
    case endDate = "end_date"
    case base, rates
}

}

What I now want, is to manipulate or ‘map’/’filter’ the inner dict ‘let rates: [String: [String: Double]]’, to convert the dict:

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

From:

[String: [String: Double]] // [Date: [Currency Code : Amount]]

To:

[String: [String: Double]] // [Currency Code: [Date : Amount]]

Effectively swapping the keys. This can easily be done by a for loop with the keys, but I need a more efficient way to achieve the task. This is so i can draw the graph in the below interface:

Graph Table View

Any help is greatly appreciated!

>Solution :

A possible way is to use reduce(into:_:):

With sample:

let rates: [String: [String: Double]] = ["2021-11-14": ["CAD": 1.1,
                                                        "USD": 1.0,
                                                        "EUR": 0.9],
                                         "2021-11-15": ["CAD": 1.11,
                                                        "USD": 1.01,
                                                        "EUR": 0.91]]

This should do the trick:

let target = rates.reduce(into: [String: [String: Double]]()) { partialResult, current in
    let date = current.key
    let dayRates = current.value
    dayRates.forEach { aDayRate in
        var currencyRates = partialResult[aDayRate.key, default: [:]]
        currencyRates[date] = aDayRate.value
        partialResult[aDayRate.key] = currencyRates
    }
}

For the logic, we iterate over each elements of rates.
For each [CurrencyCode: Amount], we iterate on them, and set them to partialResult (which at the end of the inner loop of reduce(into:_:) will be the finalResult, ie the returned value).

Outputs for print(rates) & print(target) (I just formatted them to make them easier to read):

$> ["2021-11-14": ["CAD": 1.1, "EUR": 0.9, "USD": 1.0], 
    "2021-11-15": ["USD": 1.01, "EUR": 0.91, "CAD": 1.11]]
$> ["EUR": ["2021-11-14": 0.9, "2021-11-15": 0.91], 
    "USD": ["2021-11-15": 1.01, "2021-11-14": 1.0], 
    "CAD": ["2021-11-14": 1.1, "2021-11-15": 1.11]]
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