Reputation: 443
i am figuring out a way to get the sum of values of classes which are contained in an array. My setup is as follows:
class CustomClass {
var value: Int?
init(value: Int) {
self.value = value
}
}
let object1 = CustomClass(value: 2)
let object2 = CustomClass(value: 4)
let object3 = CustomClass(value: 8)
let array: [CustomClass] = [object1, object2, object3]
My current solution is as follows:
var sumArray = [Int]()
for object in array {
sumArray.append(object.value!)
}
let sum = sumArray.reduce(0, +)
The problem is that it gets very complex with classes with many other values, does anybody know a better solution?
Upvotes: 5
Views: 5146
Reputation: 236360
I would create a protocol for your class or structures that contains a value. And change its declaration to non optional.
protocol Valueable {
var value: Int { get }
}
Then you will need to make your class conform to that protocol:
class CustomClass: Valueable {
let value: Int
init(value: Int) {
self.value = value
}
}
Now you can extend the collection protocol with a read only instance property to return the sum of all elements in your array.
extension Collection where Element: Valueable {
var sum: Int {
return reduce(0) { $0 + $1.value }
}
}
let object1 = CustomClass(value: 2)
let object2 = CustomClass(value: 4)
let object3 = CustomClass(value: 8)
let objects = [object1, object2, object3]
let sum = objects.sum // 14
edit/update:
Another option is to extend sequence and add a generic sum method that accepts a key path that its property conforms to AdditiveArithmetic
or add an associated type to the protocol that conforms to AdditiveArithmetic:
protocol Valueable {
associatedtype Value: AdditiveArithmetic
var value: Value { get }
}
extension Collection where Element: Valueable {
var sum: Element.Value { reduce(.zero) { $0 + $1.value } }
}
class CustomClass: Valueable {
let value: Decimal
init(value: Decimal) {
self.value = value
}
}
Usage:
let object1 = CustomClass(value: 123.4567)
let object2 = CustomClass(value: 12.34567)
let object3 = CustomClass(value: 1.234567)
let objects = [object1, object2, object3]
let sum = objects.sum // 137.036937
Upvotes: 1
Reputation: 439
You can compactMap your array of custom class into array of integer and then reduce that array to its sum. Like,
let sum = array.lazy.compactMap { $0.value }
.reduce(0, +)
Upvotes: 13
Reputation: 54716
You can use a single reduce
on array
.
let sumOfValues = array.reduce({$0 += ($1.value ?? 0)})
Upvotes: 3