Swift 4.2中CoreData处理:特定分类收据金额求和实现方法
在Swift 4.2中计算特定分类下所有收据的总金额
嘿,这个需求实现起来挺直观的,我给你拆解不同场景下的做法,你可以根据自己的实际数据结构调整:
第一步:先明确数据模型(假设)
首先咱们得有对应的收据和分类模型,我先写个常见的结构体示例,你可以替换成你实际用的类或者Core Data实体:
struct Category { let name: String // 你可能还有id、颜色之类的其他属性 } struct Receipt { let amount: Decimal // 推荐用Decimal处理金额,避免浮点精度问题 let category: Category // 其他属性比如交易日期、商家名称等 }
场景1:内存中的收据数组求和
如果你的收据已经存在一个数组里,用Swift的高阶函数filter+reduce就能快速搞定:
// 假设你有一个装满收据的数组 let allReceipts: [Receipt] = [ Receipt(amount: Decimal(25.5), category: Category(name: "Restaurants")), Receipt(amount: Decimal(18.0), category: Category(name: "Restaurants")), Receipt(amount: Decimal(50.0), category: Category(name: "Groceries")) ] // 目标分类名称 let targetCategory = "Restaurants" // 过滤出对应分类的收据,再累加金额 let totalAmount = allReceipts .filter { $0.category.name == targetCategory } .reduce(Decimal(0)) { accumulated, receipt in accumulated + receipt.amount } print("Restaurants分类总金额:\(totalAmount)") // 输出43.5
如果你的金额是可选类型(比如有些收据可能没记录金额),可以这么调整:
// 假设amount是可选的 struct Receipt { let amount: Decimal? let category: Category } // 求和时处理可选值 let totalAmount = allReceipts .filter { $0.category.name == targetCategory && $0.amount != nil } .reduce(Decimal(0)) { $0 + ($1.amount ?? Decimal(0)) }
场景2:Core Data存储的收据求和
如果你的收据存在Core Data里,直接用聚合查询会更高效,不用把所有数据都加载到内存:
import CoreData // 获取你的Core Data上下文 let context = /* 这里替换成你的NSManagedObjectContext实例 */ let targetCategoryName = "Restaurants" // 创建求和的FetchRequest let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Receipt") fetchRequest.predicate = NSPredicate(format: "category.name == %@", targetCategoryName) fetchRequest.resultType = .dictionaryResultType // 定义求和表达式 let sumExpression = NSExpressionDescription() sumExpression.name = "totalAmount" sumExpression.expression = NSExpression(forFunction: "sum:", arguments: [NSExpression(forKeyPath: "amount")]) sumExpression.expressionResultType = .decimalAttributeType fetchRequest.propertiesToFetch = [sumExpression] // 执行查询 do { let results = try context.fetch(fetchRequest) as! [[String: Decimal]] if let total = results.first?["totalAmount"] { print("Restaurants分类总金额:\(total)") } else { print("该分类下没有任何收据") } } catch { print("求和失败:\(error.localizedDescription)") }
一些额外的小提示
- 大小写不敏感匹配:如果分类名称不需要区分大小写(比如"restaurants"和"Restaurants"算同一个),可以把过滤条件改成:
$0.category.name.localizedCaseInsensitiveCompare(targetCategory) == .orderedSame - 避免浮点误差:一定要用
Decimal而不是Double处理金额,不然像0.1+0.2这种计算会出现精度问题。
内容的提问来源于stack exchange,提问作者Hissah D
相关产品推荐
相关产品推荐

