Posted at

NSPredicateフィルタリング

More than 5 years have passed since last update.

例えば下記のようなMealMenu型要素を複数もつNSArray *todaysMenuがいるとしましょう。


todaysMenu

// recipeName, calory, dishes

(
"sandwitch, 500, (\n BLT,\n \"lemon soda\"\n)",
"curry, 1800, (\n \"beaf curry\",\n salad,\n \"lemon soda\"\n)",
"ramen, 1100, (\n \"miso ramen\",\n water\n)"
)

todaysMenuを1000kCalオーバーのメニューのみで構成された配列としなさい


通常、


forLoop

NSMutableArray *dishes = [NSMutableArray array];    

for (MealMenu *menu in todaysMenu) {
if (menu.calory > 1000) {
[dishes addObject:menu];
}
}
todaysMenu = dishes;

とか


enumeration

__block NSMutableArray *weakDishes = [NSMutableArray array];

[todaysMenu enumerateObjectsUsingBlock:^(MealMenu *menu, NSUInteger idx, BOOL *stop) {
if (menu.calory > 1000) {
[weakDishes addObject:menu];
}
}];
todaysMenu = weakDishes;

など、一旦NSMutableArrayのインスタンスを新規に追加して対応することが考えられます。

(NSArrayは直接removeできないし)

NSPredicateを利用すると、


filterUsingPredicate

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"calory > 1000"];

[todaysMenu filterUsingPredicate:predicate];

楽です。

しかも無駄なインスタンスも生成しなくてすむ。

…しかしこれじゃあまりにもハードコーディング。

そこで、


filterUsingPredicateTemplate

NSDictionary *evaluationDic = @{@"THRESHOLD": @1000};

NSPredicate *predicateTemplate = [NSPredicate predicateWithFormat:@"%K > $THRESHOLD", @"calory"];

NSPredicate *predicate = [predicateTemplate predicateWithSubstitutionVariables:evaluationDic];
[todaysMenu filterUsingPredicate:predicate];


こうすると外部制御の検討もできて良い感じになります。