Robby
Robby

Reputation: 207

How to sum the Value from the same Key using a Dictionary?

I have a dictionary the looks like this:

(value: 21.0, id: "JdknnhshyrY56AXQcAiLcYtbVlz2") ---> This has a second entry
(value: 18.0, id: "nIvb519nNfMtlVNnsQJ5w4bRbFp2")
(value: 14.0, id: "tlKqcxHdPoemwGqJsyLhERnuQ3Z2")
(value: 5.0,  id: "JdknnhshyrY56AXQcAiLcYtbVlz2")]---> This is the second entry

I want to add the value to the same id if has a duplicate entry. Something like this:

(value: 26.0, id: "JdknnhshyrY56AXQcAiLcYtbVlz2") ---> Value has added and key has become only one
(value: 18.0, id: "nIvb519nNfMtlVNnsQJ5w4bRbFp2")
(value: 14.0, id: "tlKqcxHdPoemwGqJsyLhERnuQ3Z2")]

I already tried using a map method but has been working, has added the values but still multiple entries on the id keeping more than one.

How can I achieve the result.

Upvotes: 0

Views: 81

Answers (1)

nayem
nayem

Reputation: 7605

It's always advisable to convert your Dictionary (with heterogeneous type of values that eventually falls into [AnyHashable : Any] category) to a Typed object. With typed object, manipulation or other calculation become handy.

On the premise of the above statement you will do something like:

let objects = [Object]() // this would be you array with actual data
let reduced = objects.reduce(into: [Object]()) { (accumulator, object) in
    if let index = accumulator.firstIndex(where: { $0.id == object.id }) {
        accumulator[index].value += object.value
    } else {
        accumulator.append(object)
    }
}

Where the Object is:

struct Object {
    var value: Double
    let id: String
}

Now if you are wondering how would you convert your Dictionary to & from Object type, look at the complete code:

let arrayOfDictionary = [["value": 21.0, "id": "JdknnhshyrY56AXQcAiLcYtbVlz2"],
                         ["value": 18.0, "id": "nIvb519nNfMtlVNnsQJ5w4bRbFp2"],
                         ["value": 14.0, "id": "tlKqcxHdPoemwGqJsyLhERnuQ3Z2"],
                         ["value": 5.0,  "id": "JdknnhshyrY56AXQcAiLcYtbVlz2"]]

struct Object: Codable {
    var value: Double
    let id: String
}

do {
    let jsonData = try JSONSerialization.data(withJSONObject: arrayOfDictionary, options: [])
    let objects = try JSONDecoder().decode([Object].self, from: jsonData)

    let reduced = objects.reduce(into: [Object]()) { (accumulator, object) in
        if let index = accumulator.firstIndex(where: { $0.id == object.id }) {
            accumulator[index].value += object.value
        } else {
            accumulator.append(object)
        }
    }

    let encodedObjects = try JSONEncoder().encode(reduced)
    let json = try JSONSerialization.jsonObject(with: encodedObjects, options: [])
    if let reducedArrayOfDictionary = json as? [[String : Any]] {
        print(reducedArrayOfDictionary)
    }
} catch {
    print(error)
}

Upvotes: 1

Related Questions