Home > Back-end >  How to get sum from an object array by its ID - Swift
How to get sum from an object array by its ID - Swift

Time:03-10

I want to get a sum of each object which will be classified by its id.

So, my model is:

struct MyObject {
    let id: String
    var amount: Double
}

And my data are:

var myObjectArray = [
     MyObject(id: "A", amount: 1.0),
     MyObject(id: "B", amount: 0.2),
     MyObject(id: "A", amount: 0.4),
     MyObject(id: "B", amount: 0.8),
     MyObject(id: "C", amount: 2.1)
]

The results should be something like this:

myObjectArrayResults = [
     MyObject(id: "A", amount: 1.4),
     MyObject(id: "B", amount: 1.0),
     MyObject(id: "C", amount: 2.1)
]

I tried something to do like this, but it didn't work.

for (index, object2) in newObjectArray.enumerated() {
     for object in myObjectArray {
        if object2.id == object.id {
             newObjectArray[index].amount = newObjectArray[index].amount   object.amount
        } else {
             newObjectArray.append(object)
        }
    }
}

What might be wrong?

Thank you in advance for your contribution.

CodePudding user response:

You can use reduce(into:) to calculate the sums using an interim dictionary object and then map the result back to MyModel

let result = myObjectArray
    .reduce(into: [:]) { $0[$1.id, default: 0]  = $1.amount }
    .map(MyObject.init)

CodePudding user response:

You wrote:

for (index, object2) in newObjectArray.enumerated() {
     for object in myObjectArray {
        if object2.id == object.id {
             newObjectArray[index].amount = newObjectArray[index].amount   object.amount
        } else {
             newObjectArray.append(object)
        }
    }
}

But at start newObjectArray is empty, no? So it won't work. Then, the logic rest has be re-checked again.

You can do it like that with a for loop:

var newObjectArray = [MyObject]()

for object in myObjectArray {
    if let existingIndex = newObjectArray.firstIndex(where: { $0.id == object.id }) {
        newObjectArray[existingIndex].amount  = object.amount
    } else {
        newObjectArray.append(object)
    }
}

The idea, is to iterate over all the objects in myObjectArray, then find if it already exists, in which case we sum, or else we just append.

With reduced(into:_:), keeping the same kind of logic:

let reduced = myObjectArray.reduce(into: [MyObject]()) { partialResult, current in
    if let existingIndex = partialResult.firstIndex(where: { $0.id == current.id }) {
        partialResult[existingIndex].amount  = current.amount
    } else {
        partialResult.append(current)
    }
}
  • Related