I asked a similar question here: Getting the sum of an array of doubles in swift
but I still haven\'t gotten to a solution. Since the last question I changed my core
In your current code, you're attempting to cast logsArray
as an array of doubles when it's in fact an array of NSManagedObject
s. That's why you're getting an error when you attempt to reduce
the array.
To get the sum of the double values associated with your "totalWorkTimeInHours" key in Core Data, you have to access the "totalWorkTimeInHours" key from each NSManagedObject
returned from your fetch request then add them together, ex:
override func viewDidLoad() {
super.viewDidLoad()
//CoreData
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let managedContext : NSManagedObjectContext = appDelegate.managedObjectContext!
var fetchRequest = NSFetchRequest(entityName: "Log")
fetchRequest.returnsObjectsAsFaults = false;
var results: NSArray = managedContext.executeFetchRequest(fetchRequest, error: nil)!
var totalHoursWorkedSum: Double = 0
for res in results {
var totalWorkTimeInHours = res.valueForKey("totalWorkTimeInHours") as Double
totalHoursWorkedSum += totalWorkTimeInHours
}
print("Sum = \(totalHoursWorkedSum)")
}
You can use reduce
to add the double values of the fetched managed objects.
In the "combining closure" you have to get the double value of the totalWorkTimeInHours
attribute:
let fetchRequest = NSFetchRequest(entityName: "Log")
var error : NSError?
let results = managedContext.executeFetchRequest(fetchRequest, error: &error)
if let logs = results as? [Log] {
let totalHoursWorkedSum = reduce(logs, 0.0) { $0 + $1.totalWorkTimeInHours.doubleValue }
println(totalHoursWorkedSum)
} else {
println("fetch failed: \(error?.localizedDescription)")
}
Alternatively you can use "Key-Value Coding" to sum the double values in the array of fetched objects. This is quite similar to Lyndseys's answer, only without an explicit loop:
let fetchRequest = NSFetchRequest(entityName: "Log")
var error : NSError?
if let results = managedContext.executeFetchRequest(fetchRequest, error: &error) {
let logs = results as NSArray
let sum = logs.valueForKeyPath("@sum.totalWorkTimeInHours") as NSNumber
let totalHoursWorkedSum = sum.doubleValue
println(totalHoursWorkedSum)
} else {
println("fetch failed: \(error?.localizedDescription)")
}
But there is a better way: You create an "expression description" for the sum of all totalWorkTimeInHours values:
let expressionDesc = NSExpressionDescription()
expressionDesc.name = "sumOftotalWorkTimeInHours"
expressionDesc.expression = NSExpression(forFunction: "sum:",
arguments:[NSExpression(forKeyPath: "totalWorkTimeInHours")])
expressionDesc.expressionResultType = .DoubleAttributeType
and then a fetch request which fetches only this sum:
let fetchRequest = NSFetchRequest(entityName: "Log")
fetchRequest.propertiesToFetch = [expressionDesc]
fetchRequest.resultType = .DictionaryResultType
var error : NSError?
if let results = managedContext.executeFetchRequest(fetchRequest, error: &error) {
let dict = results[0] as [String:Double]
let totalHoursWorkedSum = dict["sumOftotalWorkTimeInHours"]!
println(totalHoursWorkedSum)
} else {
println("fetch failed: \(error?.localizedDescription)")
}
The advantage is that the sum is calculated on the SQLite level, you don't have to fetch all the objects into memory.
A possible disadvantage is that this request only fetches the values that are stored in the persistent store, and ignores any unsaved changes in the mangaged object context.