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)
}
}