Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which has faster performance indexesOfObjectsPassingTest or filteredArrayUsingPredicate?

Tags:

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?

like image 819
Henry Heleine Avatar asked Jan 16 '14 08:01

Henry Heleine


1 Answers

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; } 
like image 143
Martin R Avatar answered Oct 24 '22 06:10

Martin R