我在这里问了一个类似的问题:Getting the sum of an array of doubles in swift
但我还没有找到解决方案。自上一个问题以来,我将核心数据属性类型更改为double。问题是这个。如何获得存储在核心数据中的所有双打的总和?
现在我有:
// Get 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)!
//attempt to type cast a logs array
var logs = managedContext.executeFetchRequest(fetchRequest, error: nil)!
var logsArray = logs as NSArray as [Double]
var totalHoursWorkedSum = logsArray.reduce(0, combine: +)
//this builds, but crashes the app with 'EXC_BAD_INSTRUCTION' when I try to set a label.text with 'totalHoursWorkedSum'
我真的不确定还有什么可以尝试,所以我对任何可能实现相同目标的不同方法持开放态度。
以下是我获取和存储原始值的方法:
//Time logging
var punchInTime : NSDate = punchTimes.objectForKey("punchInTime") as NSDate
var punchOutTime = NSDate()
var totalWorkTime = NSDate().timeIntervalSinceDate(punchInTime)
//"punchInTime" is stored in NSUserDefaults
var totalWorkTimeInHoursNotRounded = (totalWorkTime/60/60)
var totalWorkTimeInHours = Double(round(1000*totalWorkTimeInHoursNotRounded)/1000)
//the rounded form of the above
//format a date
var dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = .FullStyle
//Save to CoreData
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let managedContext : NSManagedObjectContext = appDelegate.managedObjectContext!
let entity = NSEntityDescription.entityForName("Log", inManagedObjectContext: managedContext)
var newLog = DataModel(entity: entity!, insertIntoManagedObjectContext: managedContext)
newLog.totalWorkTimeInHours = totalWorkTimeInHours
newLog.dateString = dateFormatter.stringFromDate(NSDate())
managedContext.save(nil)
punchTimes.objectForKey("punchInTime") == nil
答案 0 :(得分:11)
您可以使用reduce
添加获取的托管对象的双精度值。
在"结合封闭"你必须得到totalWorkTimeInHours
的双倍值
属性:
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)")
}
或者您可以使用"键值编码"总结中的双重值 获取对象的数组。这与Lyndseys的答案非常相似,只是没有 显式循环:
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)")
}
但有更好的方法:你创建了一个 "表达描述"对于所有totalWorkTimeInHours值的总和:
let expressionDesc = NSExpressionDescription()
expressionDesc.name = "sumOftotalWorkTimeInHours"
expressionDesc.expression = NSExpression(forFunction: "sum:",
arguments:[NSExpression(forKeyPath: "totalWorkTimeInHours")])
expressionDesc.expressionResultType = .DoubleAttributeType
然后一个获取请求只获取此总和:
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)")
}
优点是总和是在SQLite级别上计算的,您不必这样做 将所有对象提取到内存中。
可能的缺点是此请求仅提取存储的值 在持久性存储中,并忽略受管对象上下文中任何未保存的更改。
答案 1 :(得分:2)
在您当前的代码中,当您实际上是logsArray
的数组时,您试图将NSManagedObject
转换为双精度数组。这就是您尝试reduce
数组时出现错误的原因。
要获取与Core Data中“totalWorkTimeInHours”键相关联的double值的总和,您必须从获取请求返回的每个NSManagedObject
访问“totalWorkTimeInHours”键,然后将它们添加到一起,例如:
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)")
}