Bhavin Bhadani
Bhavin Bhadani

Reputation: 22374

Array of dictionaries: Add values if find identical in to single dictionary Swift

I have an array of structure like this

[["grocery_section": "other", "partial_quantity": "0", "name": "Ground turmeric", "unit": "teaspoons", "whole_quantity": "1"],
["grocery_section": "other", "partial_quantity": "", "name": "I", "unit": "cups", "whole_quantity": "1"],
["grocery_section": "other", "partial_quantity": "", "name": "I", "unit": "cups", "whole_quantity": "2"]]

Now, I want to find identical entries from ingredients that have the same key-value pair in that section and If found, want to add quantity into one and make one ingredient. You can check above array where the section name is "OTHER" and check ingredients there. I want to merge that 2 identical ingredients into a single one with quantity 1+1 = 2. So, the final result should be like

[["grocery_section": "other", "partial_quantity": "0", "name": "Ground turmeric", "unit": "teaspoons", "whole_quantity": "1"],
["grocery_section": "other", "partial_quantity": "", "name": "I", "unit": "cups", "whole_quantity": "3"]]

What I tried is loop here but I don't think its efficient way. So, Is there any better way to pull this thing off?

My Code

    guard let first = ingredients.first else {
        return [] // Empty array
    }

    var uniqueIngredients: [[String:String]] = [first] // Keep first element

    for elem in ingredients.dropFirst() {
        let equality = ingredients.compactMap { $0["name"] == elem["name"] }.count
        if equality > 1 {
            // SAME NAME FOR 2 INGREDIENT FOUND
            // COMBINE BOTH OBJECT
        } else {
            // NEW NAME
            // ADD NEW OBJECT
        }
   }

Upvotes: 0

Views: 73

Answers (1)

vadian
vadian

Reputation: 285160

  • Group the array to a dictionary by name
  • Create a variable result
  • Enumerate the dictionary. If there is more than one item in value sum up the quantities and append only one item

The code assumes that the keys name and whole_quantity exist in all records and the value for key whole_quantity can be converted to Int

let array = [["grocery_section": "other", "partial_quantity": "0", "name": "Ground turmeric", "unit": "teaspoons", "whole_quantity": "1"],
             ["grocery_section": "other", "partial_quantity": "", "name": "I", "unit": "cups", "whole_quantity": "1"],
             ["grocery_section": "other", "partial_quantity": "", "name": "I", "unit": "cups", "whole_quantity": "2"]]

let groupedDictionary = Dictionary(grouping: array, by: {$0["name"]!})
var result = [[String:String]]()
for (_, value) in groupedDictionary {
    if value.isEmpty { continue }
    else if value.count == 1 {
        result.append(value[0])
    } else {
        let totalQuantity = value.map{Int($0["whole_quantity"]!)!}.reduce(0, +)
        var mutableValue = value[0]
        mutableValue["whole_quantity"] = String(totalQuantity)
        result.append(mutableValue)
    }
}

Upvotes: 2

Related Questions