这是一个设计问题。假设我有一个包含2个实体的CoreData模型 - 项目和公式。
项目有3个数字属性“X”,“Y”和“Z”,以及与“公式”实体的一对一关系。
公式有一个字符串属性,包含“(X * Y * Z)**(1.0 / 3)”或“Pi * X ** 3 / 3.0”等表达式。任何使用常数的简单算术,标准运算符(加法,减法,乘法,除法,幂,括号)和“X”“Y”和“Z”符号。
现在我的任务非常期待 - 如何为“Item”实体设置一个新属性,称为“value”,它将通过将XY和Z值插入相关的“公式”来计算,并进行评估表达。
考虑: 1.可能有数百万个“物品”实体,以及数百个“公式”。 2.我可以控制创建公式字符串的格式 - 我可以让人们键入“$ X + $ Y”而不是“X + Y”,如果这样可以减少事情。 3.我需要进一步计算快速计算项目子集的“价值”统计数据(总和,中位数,平均数等)。
我的问题: 1.一般如何去做。添加一个真实数字“值”属性来缓存计算结果,或者一个计算属性,在读取时重新计算? 2.如何使用NSExpression插入值而不是像“X”“Y”“Z”那样的变量符号。 3.我可以以某种方式预先创建一个NSExpression并将其作为“公式”的另一个属性进行缓存,并在以后使用它而不是解析和评估每个项目的公式吗?如何在CoreData中存储已解析的NSExpression?
我知道这是一个很多子问题的大问题。任何提示都将不胜感激!
答案 0 :(得分:1)
实际答案很少......所以我最终使用了来自Dave Delong的名为DDMathParser的开源评估程序,它的工作原理与NSExpression非常相似,但使用起来更简单,并且可扩展。
在我的模型中,我为我的“Item”和我的“Formula”子类化了NSManagedObject。我添加了每个计算的只读属性,如下所示:
“MyItem.m”中的
// Define dependencies of the calculated value upon other attributes, for KVO. Whenever any of the provided keypaths change, there is a need to recalculate.
+ (NSSet *)keyPathsForValuesAffectingCalculatedValue {
return [NSSet setWithObjects:@"x", @"y", @"z", @"formula.expression", nil];
}
- (double) calculatedValue {
NSError *error = nil;
NSDictionary *s = [NSDictionary dictionaryWithObjectsAndKeys: @(self.x) , @"X", @(self.y) , @"Y", @(self.z), @"Z", nil];
NSNumber *result = [[DDMathEvaluator defaultMathEvaluator] evaluateExpression:self.formula.expression withSubstitutions:s error:&error];
if (error)
NSLog(@"Error calculating value: %@", error);
else
return [result doubleValue];
}
和我的“MyFormula.m”:
@dynamic expressionParsingError;
+ (NSSet *)keyPathsForValuesAffectingExpression {
return [NSSet setWithObjects:@"formulaString", nil];
}
- (DDExpression *)expression {
NSError *err = nil;
DDExpression *exp = [DDExpression expressionFromString:self.volumeFormula error:&err];
self.expressionParsingError = err;
return err ? nil : exp;
}
我不存储甚至缓存已解析的表达式和计算结果。我只缓存一个错误对象,用于显示和报告错误公式的解析错误。我将DDMathParser引擎转换为DDExpression时收到此NSError。
我可以使这些属性成为模型的正确瞬态属性,但由于性能良好,我认为现在没有必要这样做。我可能会在将来的某个时候重新尝试我的解决方案。
然后,在我的表和算法中,我可以简单地将我的MacOS-X app表列绑定到“calculatedValue”属性,并且它将根据需要自动计算(尽管结果不会被缓存)。
将来,我可以删除对DDMathParser的需求,然后再回到NSExpression。但是--- DDMathParser让我做了很棒的事情,比如在用户编辑公式时立即显示解析错误。我还提供了一个小“沙箱”,用户可以使用假数字测试他们的公式,并看到他们的公式在将其应用于数百万件物品之前工作正常。
在我相当古老的MacBookPro(2009)上分析10000件物品是很直接的。请记住,基于单元格的表不会评估整个列 - 只是可见部分。
我希望这会有所帮助......