0

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

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

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

现在我的任务非常值得期待——如何为“项目”实体设置一个新属性,称为“值”,将通过将 XY 和 Z 值插入相关的“公式”并评估表达式来计算。

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

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

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

4

1 回答 1

1

实际答案很少……所以我最终使用了来自 Dave Delong 的名为DDMathParser的开源评估器,它的工作原理与 NSExpression 非常相似,但使用起来更简单,并且可扩展。

在我的模型中,我将 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;
}

我不存储甚至不缓存解析的表达式和计算结果。我只缓存一个错误对象,用于显示和报告错误公式的解析错误。在将其转换为 DDExpression 时,我从 DDMathParser 引擎收到此 NSError。

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

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

将来,我可以消除对 DDMathParser 的需求,并回到 NSExpression。但是 --- DDMathParser 让我可以做一些很棒的事情,比如在用户编辑公式时立即显示解析错误。我还提供了一个小“沙箱”,用户可以在其中使用假数字测试他们的公式,并在将其应用于数百万个项目之前查看他们的公式是否正常工作。

在我相当旧的 MacBookPro (2009) 上分析 10000 个项目是一种即时性。请记住,基于单元格的表格不会评估整个列 - 只是可见部分。

我希望这有帮助...

于 2014-09-07T15:42:29.413 回答