Prerna chavan
Prerna chavan

Reputation: 3249

Multiple conditions in NSPredicate

How to use multiple conditions with NSPredicate?

I am using this but not getting anything in the returned array .

NSPredicate *placePredicate = [NSPredicate predicateWithFormat:@"place CONTAINS[cd] %@ AND category CONTAINS[cd] %@ AND ((dates >= %@) AND (dates <= %@)) AND ((amount >= %f) AND (amount <= %f))",placeTextField.text,selectedCategory,selectedFromDate,selectedToDate,[amountFromTextField.text floatValue],[amountToTextField.text floatValue]];

NSArray *placePredicateArray = [dataArray filteredArrayUsingPredicate:placePredicate];

NSLog(@"placePredicateArray %@", placePredicateArray);

The amount and the category can be empty sometimes. How should I construct the NSPredicate?

Upvotes: 13

Views: 14211

Answers (3)

Singhak
Singhak

Reputation: 8896

Suppose a class Person with attributes "name", "age", "income"

"personArray" is array of class Person

NSPredicate *mypredicate = [NSPredicate predicateWithBlock:^BOOL(personObj Person, NSDictionary *bindings) {
     NSNumber *age = personObj.age;
     String *name = personObj.name;
     NSNumber *income = personObj.income
     BOOL result = (age > 20 && name == "Stack" && income >40000);
     return result;
}];

NSArray *filteredArray = [personArray filteredArrayUsingPredicate: mypredicate];

For further you can read this article Array Filter Using Blocks

In Swift

let filterArray = personArray.filter
            { person in
           let age = personObj.age;
           let name = personObj.name;
           let income = personObj.income
           BOOL result = (age > 20 && name == "Stack" && income >40000);
          return result;
        }

Upvotes: 0

deanWombourne
deanWombourne

Reputation: 38475

You can build your placesPredicate using other NSPredicate objects and the NSCompoundPredicate class

Something like :

NSPredicate *p1 = [NSPredicate predicateWithFormat:@"place CONTAINS[cd] %@", placeTextField.text];
NSPredicate *p2 = [NSPredicate predicateWithFormat:@"category CONTAINS[cd] %@", selectedCategory];
NSPredicate *p3 = [NSPredicate predicateWithFormat:@"(dates >= %@) AND (dates <= %@)", selectedFromDate,selectedToDate];
NSPredicate *p4 = [NSPredicate predicateWithFormat:@"(amount >= %f) AND (amount <= %f)", [amountFromTextField.text floatValue],[amountToTextField.text floatValue]]; 

NSPredicate *placesPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[p1, p2, p3, p4]];

Now, if you are missing category for example you can just use a dummy YES predicate to replace it :

NSPredicate *p2;
if (selectedCategory) {
    p2 = [NSPredicate predicateWithFormat:@"category CONTAINS[cd] %@", selectedCategory];
} else {
    p2 = [NSPredicate predicateWithBool:YES]
}

Upvotes: 30

DRVic
DRVic

Reputation: 2481

I would tend to handle this one piecemeal. That is,

placePredicate = [NSPredicate predicateWithFormat:@"place CONTAINS[cd] %@",placeTextField.text];
NSMutableArray *compoundPredicateArray = [ NSMutableArray arrayWithObject: placePredicate ]; 

if( selectedCategory != nil ) // or however you need to test for an empty category
    {
    categoryPredicate = [NSPredicate predicateWithFormat:@"category CONTAINS[cd] %@",selectedCategory];
    [ compoundPredicateArray addObject: categoryPredicate ];
    }

// and similarly for the other elements.  

Note that I don't bother even putting into the array the predicate for category (or anything else) when I know there isn't one.

// Then
    NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
                                  compoundPredicateArray ];

And if I were planning to do it a lot, I wouldn't use the format method, but keep around the building blocks and just change whatever changes between uses.

Upvotes: 13

Related Questions