Objective c 使用NSExpression对CoreData进行列计算字段评估。变量替换、公式存储

Objective c 使用NSExpression对CoreData进行列计算字段评估。变量替换、公式存储,objective-c,regex,core-data,nsexpression,Objective C,Regex,Core Data,Nsexpression,这是一个设计问题。假设我有一个包含两个实体的CoreData模型-项和公式 项有3个数字属性“X”、“Y”和“Z”,以及与“公式实体的一对一关系 公式有一个字符串属性,包含“(X*Y*Z)**(1.0/3)”或“Pi*X**3/3.0”等表达式。任何使用常量、标准运算符(加减、乘法、除法、幂、括号)和“X”、“Y”和“Z”符号的简单算术 现在我的任务是非常期待的——如何为“Item”实体设置一个新属性,称为“value”,它将通过将X、Y和Z值插入相关的“公式”并计算表达式来计算 考虑事项: 1

这是一个设计问题。假设我有一个包含两个实体的CoreData模型-公式

有3个数字属性“X”、“Y”和“Z”,以及与“公式实体的一对一关系

公式有一个字符串属性,包含“(X*Y*Z)**(1.0/3)”或“Pi*X**3/3.0”等表达式。任何使用常量、标准运算符(加减、乘法、除法、幂、括号)和“X”、“Y”和“Z”符号的简单算术

现在我的任务是非常期待的——如何为“Item”实体设置一个新属性,称为“value”,它将通过将X、Y和Z值插入相关的“公式”并计算表达式来计算

考虑事项: 1.可能有数百万个“项目”实体和数百个“公式”。 2.我可以控制公式字符串的创建格式——如果方便的话,我可以让人们输入“$X+$Y”而不是“X+Y”。 3.我需要进一步快速计算项目子集的“价值”统计数据(总和、中位数、标准差、平均值等)

我的问题是: 1.一般来说,该怎么做。添加一个实数值“值”属性以缓存计算结果,或添加一个读取时重新计算的计算属性? 2.如何使用NSExpression插入值,而不是像“X”“Y”“Z”这样的变量符号。 3.我是否可以预先创建一个NSExpression并将其缓存为“Formula”的另一个属性,然后使用它,而不是解析和计算每个项的公式?如何在CoreData中存储解析的NSExpression


我知道这是一个有很多子问题的大问题。任何提示都将不胜感激

实际答案很少……因此我最终使用了一个名为Dave Delong的开源计算器,它的工作原理与NSExpression非常相似,但使用起来更简单,而且是可扩展的

在我的模型中,我为我的“Item”和“Formula”子类化了NSManagedObject。我添加了一个计算的只读属性,如下所示:

在“MyItem.m”中

在我的“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;
}
我不存储甚至缓存解析的表达式和计算结果。我只缓存一个错误对象,用于显示和报告错误公式的解析错误。在将其转换为DDExpression时,我从DDMathParser引擎接收到这个N错误

我可以将这些属性设置为模型的适当瞬态属性,但由于性能良好,我认为现在没有必要这样做。我可能会在将来的某个时候重新迭代我的解决方案

然后,在我的表和算法中,我可以简单地将我的MacOS-X应用程序表列绑定到“calculatedValue”属性,它将根据需要自动计算(尽管结果不会被缓存)

将来,我可以不再需要DDMathParser,转而使用NSExpression。然而--DDMathParser让我可以做一些很棒的事情,比如在用户编辑公式时立即显示解析错误。我还提供了一个小“沙盒”,用户可以在这里用假数字测试他们的公式,看看他们的公式在应用到数百万项之前是否工作良好

在我比较老的MacBookPro(2009)上,分析10000个项目是一种“即时的”。请记住,基于单元格的表不会计算整个列,只计算可见部分

我希望这有助于

@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;
}