1

I have an array of objects, which each have a category and an amount, as below:

Record("Bills", 150.00), Record("Groceries", 59.90), etc...

I'd like to use reduce to populate a [String:[CGFloat]] dictionary.

It should be like this:

[ "Bills" : [150.00, 140.00, 200.00] , "Groceries" : [59.90, 40.00, 60.00] ]

However, I can't figure out how to achieve this elegantly.

I've tried (with no success):

var dictionary = [String:[CGFloat]]()
dictionary = expenses_week.reduce(into: [:]) { (result, record) in
    result[record.category ?? "", default: 0].append((CGFloat(record.amount)))

The above returns the error: "Cannot subscript a value of incorrect or ambiguous type."

The closest I've gotten is:

var dictionary = [String:[CGFloat]]()
dictionary = expenses_week.reduce(into: [:]) { (result, record) in
    result[record.category ?? "", default: 0] = [(CGFloat(record.amount))]

That works, but it doesn't do what I want, obviously. :)

I would greatly appreciate your help.

0

2 Answers 2

2

Your code is almost correct. The value type of dictionary is [CGFloat], therefore the default value in the subscript operation must be an empty array, not the number 0:

let dictionary = expenses_week.reduce(into: [:]) { (result, record) in
    result[record.category ?? "", default: []].append(CGFloat(record.amount))
}

You might also consider to remove the cast to CGFloat, then the result has the type [String : [Double]].

Btw, alternative (but not necessarily more efficient) approaches would be

let dictionary = Dictionary(expenses_week.map { ($0.category ?? "", [$0.amount]) },
                            uniquingKeysWith: +)

or

let dictionary = Dictionary(grouping: expenses_week, by: { $0.category ?? "" })
    .mapValues { $0.map { $0.amount } }
Sign up to request clarification or add additional context in comments.

Comments

1
struct Record {
    let category: String
    let amount: NSNumber
}

let records = [
    Record(category: "Bills", amount: 150.00),
    Record(category: "Bills", amount: 140.00),
    Record(category: "Bills", amount: 200.00),
    Record(category: "Groceries", amount: 59.90),
    Record(category: "Groceries", amount: 40.00),
    Record(category: "Groceries", amount: 60.00),
]

let dictionary = records.reduce(into: [String:[NSNumber]](), {
    $0[$1.category] = $0[$1.category] ?? []
    $0[$1.category]?.append($1.amount)
})

print(dictionary)

1 Comment

Brilliant! Thank you, Callam!

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.