LoginSignup
25
23

More than 5 years have passed since last update.

NSPredicateフィルタリング

Posted at

例えば下記のような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];

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

25
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
23