WishIHadThreeGuns
WishIHadThreeGuns

Reputation: 1479

Map a Dictionary with array of values

I want to convert a dictionary to an Array, by showing each [String: [String]] element as a string in the array (but the value may be empty).

So ["A": ["1","2"], "b": [], "c": ["5", "6"]] will give ["b", "A1", "A2", "c5", "c6"].

I want to use map to do this, as the code I have feels unwieldy:

let messages: [String: [String]] = ["A": ["1","2"], "b": [], "c": ["5", "6"]]

var result: [String] = []

for message in messages {
    if !message.value.isEmpty {
        for value in message.value {
            result.append(message.key + value)
        }
    } else {
        result.append(message.key)
    }
}

How can I create the solution using map?

Upvotes: 0

Views: 195

Answers (2)

Larme
Larme

Reputation: 26096

A possible solution is to use reduce(into:_:), (I prefer this one):

let messages: [String: [String]] = ["A": ["1","2"], "b": [], "c": ["5", "6"]]

let output = messages.reduce(into: [String]()) { result, current in
    guard !current.value.isEmpty else { result.append(current.key); return }
    let sub = current.value.map { current.key + $0 }
    result.append(contentsOf: sub)
}

print("Output: \(output)")

Output: $> Output: ["c5", "c6", "A1", "A2", "b"]

With a map and a flatMap, I found it less intuitive:

let output2 = messages.map { element -> [String] in
    guard !element.value.isEmpty else { return [element.key] }
    let sub = element.value.map { element.key + $0 }
    return sub
}.flatMap { $0 }

print("Output2: \(output2)")

Which then can be simplified with a direct call to flatMap, but that (map + flatMap) was to show the process, since this one will save you an iteration (you do only one instead of two):

let output3 = messages.flatMap { element -> [String] in
    guard !element.value.isEmpty else { return [element.key] }
    let sub = element.value.map { element.key + $0 }
    return sub
}
print("Output3: \(output3)")

I made the closure explicit enough, but that's up to you if you want to shorten them with ternary if etc.

Upvotes: 1

Mikhail Vasilev
Mikhail Vasilev

Reputation: 760

A little bit shortened version using map

let messages: [String: [String]] = ["A": ["1","2"], "b": [], "c": ["5", "6"]]

let result = messages.map { dict in
    return dict.value.isEmpty ? ["\(dict.key)"] : dict.value.map { "\(dict.key)\($0)" }
}.flatMap{$0}

Upvotes: 1

Related Questions