0

これは一種の設計上の問題です。ItemFormulaの 2 つのエンティティを持つ CoreData モデルがあるとします。

項目には、「X」、「Y」、「Z」の 3 つの数値属性と、「Formula」エンティティとの対 1 関係があります。

数式には、"(X*Y*Z)**(1.0/3)" や "Pi * X**3 / 3.0" などの式を含む 1 つの文字列属性があります。定数、標準演算子 (加算、減算、 、乗算、除算、累乗、括弧)、および「X」、「Y」、および「Z」記号。

今、私の仕事は非常に期待されています---「値」と呼ばれる「項目」エンティティに新しい属性を設定する方法は、XY 値と Z 値を関連する「式」に差し込んで式を評価することによって計算されます。

考慮事項: 1. 何百万もの "Item" エンティティと、何百もの "Formula" が存在する場合があります。2. フォーミュラ文字列が作成されるフォーマットを制御できます --- 問題が解決する場合は、"X+Y" の代わりに "$X+$Y" と入力することもできます。3.アイテムのサブセット全体に起因する「値」の統計をさらに計算する必要があります(合計、標準偏差の中央値、平均など)。

私の質問: 1. 一般的にどのように対処するか。計算結果をキャッシュする実数値の「値」属性を追加するか、読み取り時に再計算する計算プロパティを追加しますか? 2. 「X」「Y」「Z」などの可変記号の代わりに値をプラグインするために NSExpression を使用する方法。3. 何らかの方法で NSExpression を事前に作成し、それを「Formula」の別の属性としてキャッシュして、各アイテムの式を解析して評価する代わりに後で使用できますか? 解析された NSExpression を CoreData に格納するにはどうすればよいですか?

これは多くの副次的な質問を伴う大きな質問であることは承知しています。ヒントをいただければ幸いです。

4

1 に答える 1

1

実際の回答はまばらだったので、Dave Delong のDDMathParserと呼ばれるオープン ソースの評価ツールを使用することになりました。

私のモデルでは、"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;
}

解析された式と計算結果を保存したり、キャッシュしたりしません。不適切な数式の解析エラーを表示および報告するために、エラー オブジェクトを 1 つだけキャッシュします。DDMathParser エンジンを DDExpression に変換すると、この NSError を受け取ります。

これらのプロパティをモデルの適切な一時属性にすることもできましたが、最初はパフォーマンスが良好だったので、今はそれを行う必要はないと判断しました。私はおそらく将来いつか私の解決策を繰り返すでしょう。

次に、テーブルとアルゴリズムで、MacOS-X アプリ テーブルの列を「calculatedValue」プロパティにバインドするだけで、必要に応じて自動的に計算されます (ただし、結果はキャッシュされません)。

将来的には、DDMathParser の必要性を取り除き、NSExpression に戻すことができます。しかし --- DDMathParser を使用すると、ユーザーが数式を編集するとすぐに解析エラーを表示するなど、素晴らしいことができます。私はまた、ユーザーが偽の数字で数式をテストし、数百万の項目に適用する前に数式が正常に機能することを確認できる小さな「サンドボックス」も提供します。

私のかなり古い MacBookPro (2009) では、10000 個のアイテムを分析するのはすぐにできます。セル ベースのテーブルは、列全体を評価するのではなく、表示されている部分だけを評価することに注意してください。

これが役立つことを願っています...

于 2014-09-07T15:42:29.413 に答える