When needing to filter an NSArray to get a subset of the items in the array returned, which method is quicker more frequently and in edge cases?
The following tests (compiled in Release mode, executed on a Mac Pro) indicate that filteredArrayUsingPredicate
is slower than indexesOfObjectsPassingTest
if you use a "textual" predicate, but faster if you use block-based predicate. The fasted method in my test was a simple (fast-enumeration) loop that adds all matching objects to a mutable array.
Results for filtering an array of 10,000,000 dictionaries, where about 50% match the predicate:
8.514334 (predicateWithFormat) 4.422550 (predicateWithBlock) 5.170086 (indexesOfObjectsPassingTest) 3.154015 (fast-enumeration + mutable array)
Of course the results may be different for other predicates.
#import <Foundation/Foundation.h> NSUInteger filter1(NSArray *a) { NSPredicate *pred = [NSPredicate predicateWithFormat:@"num > 1000 AND foo == 'bar'"]; NSArray *filtered = [a filteredArrayUsingPredicate:pred]; return [filtered count]; } NSUInteger filter2(NSArray *a) { NSPredicate *pred = [NSPredicate predicateWithBlock:^BOOL(NSDictionary *obj, NSDictionary *bindings) { return ([obj[@"num"] intValue] > 1000 && [obj[@"foo"] isEqualToString:@"bar"]); }]; NSArray *filtered = [a filteredArrayUsingPredicate:pred]; return [filtered count]; } NSUInteger filter3(NSArray *a) { NSIndexSet *matching = [a indexesOfObjectsPassingTest:^BOOL(NSDictionary *obj, NSUInteger idx, BOOL *stop) { return ([obj[@"num"] intValue] > 1000 && [obj[@"foo"] isEqualToString:@"bar"]); }]; NSArray *filtered = [a objectsAtIndexes:matching]; return [filtered count]; } NSUInteger filter4(NSArray *a) { NSMutableArray *filtered = [NSMutableArray array]; for (NSDictionary *obj in a) { if ([obj[@"num"] intValue] > 1000 && [obj[@"foo"] isEqualToString:@"bar"]) { [filtered addObject:obj]; } } return [filtered count]; } void testmethod(NSArray *a, NSUInteger(*method)(NSArray *a)) { @autoreleasepool { NSDate *t1 = [NSDate date]; NSUInteger count = method(a); NSDate *t2 = [NSDate date]; NSLog(@"%f", [t2 timeIntervalSinceDate:t1]); } } int main(int argc, const char * argv[]) { @autoreleasepool { NSMutableArray *a = [NSMutableArray array]; for (int i = 0; i < 10000000; i++) { [a addObject:@{@"num": @(arc4random_uniform(2000)), @"foo":@"bar"}]; } testmethod(a, filter1); testmethod(a, filter2); testmethod(a, filter3); testmethod(a, filter4); } return 0; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With