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.

Cal
  • 422
  • 6
  • 20
David Spry
  • 119
  • 2
  • 8

2 Answers2

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 } }
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
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)
Callam
  • 11,409
  • 2
  • 34
  • 32