2

This is a simplified representation of my problem using Realm database.

struct Foo: CustomStringConvertible {
    var fooId: Int
    var fooName: String
    var bars: [String]

    var description: String {
        return "Foo: \(fooId) \(fooName) \(bars)"
    }
}

var ff = [Foo]()

var f1 = Foo(fooId: 1, fooName: "A", bars: ["A1", "A2", "A3"])
var f2 = Foo(fooId: 2, fooName: "B", bars: ["B1"])
var f3 = Foo(fooId: 3, fooName: "A", bars: ["A4", "A5"])
var f4 = Foo(fooId: 4, fooName: "B", bars: ["B2", "B3", "B4"])
var f5 = Foo(fooId: 5, fooName: "B", bars: ["B5"])
var f6 = Foo(fooId: 6, fooName: "A", bars: ["A6", "A7", "A8", "A9", "A10"])
var f7 = Foo(fooId: 7, fooName: "C", bars: ["C1", "C2", "C3"])

ff.append(contentsOf: [f1, f2, f3, f4, f5, f6, f7])

I want to flatMap or compactMap the Foo array based on fooName, so I'm able to construct a Map of fooName -> bars

A -> ["A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10"] B -> ["B1", "B2", "B3", "B4", "B5"] C -> ["C1", "C2", "C3"]

3
  • 1
    What is your problem? Commented Mar 14, 2019 at 21:21
  • @Magnas I'm going to post another question regarding my Realm issue soon. The answer in this post works for Swift arrays, and it's exactly what I asked for, but I'm unable to apply it to Realm objects as there is no support for Dictionary and grouping. Commented Mar 15, 2019 at 10:10
  • @Magnas please check stackoverflow.com/questions/55182360/… Commented Mar 15, 2019 at 12:12

2 Answers 2

4

You can reduce(into:_:):

let results = ff.reduce(into: [String: [String]]()) { result, foo in
    result[foo.fooName, default: []].append(contentsOf: foo.bars)
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks. Could you possibly modify your answer so the expected result is a dictionary of [Foo] type arrays A -> [Foo(fooId: 1, fooName: "A", bars: ["A1", "A2", "A3"]), Foo(fooId: 3, fooName: "A", bars: ["A4", "A5"]), Foo(fooId: 6, fooName: "A", bars: ["A6", "A7", "A8", "A9", "A10"])] B -> [Foo(fooId: 2, fooName: "B", bars: ["B1"]), Foo(fooId: 4, fooName: "B", bars: ["B2", "B3", "B4"]), Foo(fooId: 5, fooName: "B", bars: ["B5"])] C -> [Foo(fooId: 7, fooName: "C", bars: ["C1", "C2", "C3"])]
let results = ff.reduce(into: [String: [Foo]](), { (result, foo) in result[foo.fooName, default: []].append(foo) }) Think this is doing the job. Now I've to tweak the way it's filtered and sorted
@Amitoj - Personally, if you wanted that, I’d do let result = Dictionary(grouping: ff) { $0.fooName }. But, with no offense, that’s not what you asked for in your question. You asked for values that are flattened arrays of bars, and my answer shows how to do that with a single call to reduce(into:_:) rather than the three calls that Sulthan's answer (+1) does. And I wouldn’t personally advise changing the question at this point because (a) that would invalidate both of our answers; and (b) you already know the answer to that question already (lol).
2

This seems fairly straightforward:

// group instances by fooName
let dict: Dictionary<String, [Foo]> = Dictionary(grouping: ff, by: { $0.fooName })
print(dict)
// flat map the [Foo] instances to [String] of their bars
let dict2: Dictionary<String, [String]> = dict.mapValues { foos in foos.flatMap { $0.bars } }
print(dict2)

or simplified:

let dict = Dictionary(grouping: ff, by: { $0.fooName })
    .mapValues { foos in foos.flatMap { $0.bars } }
print(dict)

2 Comments

Cheers Sulthan, I'll try to apply your solution on my Realm objects tomorrow and hopefully it should do the trick.
@Rob Thanks to your input, I wanted to be be more explicit about the types and somehow I thought flatMap returns a Sequence.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.