Reputation: 1699
I've the following structure:
TxnSummary * t1 = [[TxnSummary alloc] init];
t1.txnId = @"1";
t1.shortDesc = @"First one";
t1.filters = [[NSArray alloc] initWithObjects:@"F1", @"F2", nil];
TxnSummary * t2 = [[TxnSummary alloc] init];
t2.txnId = @"2";
t2.shortDesc = @"Second one";
t2.filters = [[NSArray alloc] initWithObjects:@"F1",@"F2", @"F3", nil];
TxnSummary * t3 = [[TxnSummary alloc] init];
t3.txnId = @"3";
t3.shortDesc = @"Third one";
t3.filters = [[NSArray alloc] initWithObjects:@"F1", @"F3", nil];
TxnSummary * t4 = [[TxnSummary alloc] init];
t4.txnId = @"4";
t4.shortDesc = @"Fourth one";
t4.filters = [[NSArray alloc] initWithObjects:@"F4", nil];
NSArray * xnArray = [[NSArray alloc] initWithObjects:t1,t2,t3,t4, nil];
Now if I want to find out which of the txn summaries have filters F1, then I could do this:
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"filters CONTAINS[cd] %@", @"F1"];
NSArray * filteredArray = [xnArray filteredArrayUsingPredicate:predicate];
This works well if I'm comparing for only one string, but if want to find out which all txn summaries have filters "F1", or "F2", then if I have to follow the above mechanism I'll have to create two predicates - each for F1 and F2 and then run it against the xnArray (which seems to be inefficient). I want to be able to create a list of filters strings and use that to fetch the matching txs from the xn array.
NSArray * filterStrings = [[NSArray alloc] initWithObjects:@"F1",@"F2", nil];
Does NSPredicate have functionality to achieve this or should I resort to some other method of filtering?
Appreciate your help.
Thanks, Kumar
Upvotes: 2
Views: 3954
Reputation: 2335
You can do something like:
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"filters CONTAINS[cd] %@ || filters CONTAINS[cd] %@", @"F1", @"F4"];
If you want to add all the keys that are in a array you can do something like that:
NSArray * filterStrings = [[NSArray alloc] initWithObjects:@"F1",@"F4", nil];
NSString* predicateString = [filterStrings componentsJoinedByString:@"'|| filters CONTAINS[cd] '"];
predicateString = [NSString stringWithFormat:@"filters CONTAINS[cd] '%@'",predicateString];
NSPredicate * predicate = [NSPredicate predicateWithFormat:predicateString];
NSArray * filteredArray = [xnArray filteredArrayUsingPredicate:predicate];
Upvotes: 4
Reputation: 9076
If I understand you correctly, you can achieve this by creating a compound predicate from an array of predicates, for example:
NSPredicate *newFilterPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:selectedItemIDs];
EDIT: added more detailed explanation:
Compound predicates combine predicates into one predicate. For example, if you want to filter for items that contain "F1" or "F2" you do this:
// Normally build this in some kind of loop
NSPredicate *firstPredicate = [NSPredicate predicateWithFormat:@"filter =%@", @"F1"];
NSPredicate *secondPredicate = [NSPredicate predicateWithFormat:@"filter =%@", @"F1"];
// Create the array of predicates
NSArray *arrayOfPredicates = [NSArray arrayWithObjects:firstPredicate, secondPredicate, nil];
// Create the compound predicate
NSPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:arrayOfPredicates];
There are also methods for "and" instead of "or" as well as other boolean conditions. Full reference can be found here: NSCompoundPredicate Class Reference
Hope this helps,
Dave
Upvotes: 4
Reputation: 8340
I wouldn't use NSArray to store the filters. This is a perfect book-like example for using NSSet/NSMutableSet instead. You can initialize similarly to the array:
t1.filters = [[NSSet alloc] initWithObjects:@"F1", @"F2", nil];
Then you check if that particular string exists simply by calling:
BOOL contains = [t1.filter containsObject:@"F1"];
You can now also filter the set with methods like filteredSetUsingPredicate
, objectsPassingTest
(to use with blocks) or even create intersections or unions with other sets (isSubsetOfSet
, intersectsSet
, etc). So for example you could create a new set with the searched elements and check if the set contains them:
NSSet* toFind = [[NSSet alloc] initWithObjects:@"F1", @"F3", nil];
[toFind isSubsetOfSet:t1.filters];
Searching a set is much quicker than an array because set is backed up by a Hash table, whereas an array has to be searched linearly.
Upvotes: 1
Reputation: 4270
If exact matching is OK, you could use the IN
predicate like so:
NSArray *filterStrings = [NSArray arrayWithObjects:@"F1", @"F2", nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"filters IN %@", filterStrings];
NSArray *filteredArray = [xnArray filteredArrayUsingPredicate:predicate];
Upvotes: 0