[iOS] CoreDataでデータの中から最大値/最小値や平均が欲しいとき

2012/09/22

こんにちは。きんくまです。
またまた備忘録です。

DBからNSManagedObjectでなく、EntityのAttributeの最大値や平均をもとめたいときがあります。
最初はManagedObject全部引っ張ってきて手動で計算するのかな?と思ったのですが、ちゃんとやり方がありました。
Appleのドキュメントに書いてありましたです。

Core Data Programming Guide – Fetching Specific Values

今回のコードはここに書いてあるそのまんまです。すみません、、。

やり方

やり方は通常とちょっとだけ違っていて

1. NSFetchRequestにsetResultType:NSDictionaryResultTypeとすること
2. NSExpressionDescriptionをセットすること

となってます。FetchRequestの結果は通常と同じArrayなんですが、その中身がDictionaryになってるところがポイントです。

NSExpressionDescriptionの作り方

NSExpressionDescriptionを作るのがまた少し手間ですが

1. NSExpressionを作成
評価したいAttributeをセットして、さらにそいつを引数に使い、expressionForFunction:argumentsを作る感じです。
expressionForFunction:argumentsの最初の引数は求めたいタイプ(最大値、最小値、平均など)を入れます。

そのリストはここにあります。

>> expressionForFunction:arguments:

例えば最大値なら@”max:”となります。

NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"salary"];
NSExpression *maxSalaryExpression = [NSExpression expressionForFunction:@"max:"
                                                  arguments:[NSArray arrayWithObject:keyPathExpression]];

2. NSExpressionDescriptionを作る

NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
[expressionDescription setName:@"maxSalary"];
[expressionDescription setExpression:maxSalaryExpression];
[expressionDescription setExpressionResultType:NSDecimalAttributeType];

nameはfetchで返ってくるdictionaryのキーになります。
expressionは1でつくったNSExpressionです。
expressionResultTypeはNSAttributeType一覧にあります。返ってくるdictionaryの値のタイプです。整数、小数、日付とかです。

3.NSFetchRequestにセット

最後にfetchRequestにセットして準備完了です。

[request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];

とおして書いてみる

公式のサンプルのまねして書いてみるとこんな感じ。

- (NSInteger)maxDisplayOrderValue
{
    NSFetchRequest *req = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
    [req setEntity:entity];
    [req setResultType:NSDictionaryResultType];
    
    NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"displayOrder"];
    NSExpression *maxExpression = [NSExpression expressionForFunction:@"max:" arguments:@[keyPathExpression]];
    NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
    [expressionDescription setName:@"maxDisplayOrder"];
    [expressionDescription setExpression:maxExpression];
    [expressionDescription setExpressionResultType:NSInteger32AttributeType];
    [req setPropertiesToFetch:@[expressionDescription]];
    
    NSError *error = nil;
    NSArray *obj = [self.managedObjectContext executeFetchRequest:req error:&error];
    NSInteger maxValue = NSNotFound;
    if(obj == nil){
        NSLog(@"error");
    }else if([obj count] > 0){
        maxValue = [obj[0][@"maxDisplayOrder"] integerValue];
    }
    return maxValue;
}
LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

LINEスタンプ作りました!
毎日使える。とぼけたウサギ。LINEスタンプ販売中! 毎日使える。とぼけたウサギ

ページトップへ戻る