Which has faster performance indexesOfObjectsPassingTest or filteredArrayUsingPredicate?
The following tests (compiled in Release mode, executed on a Mac Pro) indicate thatfilteredArrayUsingPredicate
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;
}
iOS - searching in a large NSArray is slow
You should try to use the profiler to find the weakest line,
but I assume that the problem is that predicate block is evaluated for every entry every time.
I would suggest you to create your own wrapper class for ABRecordRef (let's say RecordWrapper), which will contain link to ABRecordRef with whole data and cache some frequent used and important values (e.g. fullName), you can obtain it once while loading list of contacts.
Then if you have an array of RecordWrapper* objects you can filter simply by calling
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"fullName contains[c] %@", searchText];
searchResults = [self.allContactsWrappers filteredArrayUsingPredicate:resultPredicate];
This should significantly increase filtering speed.
Predicate for range of NString in a Array
You could basically split the string and search for the array on the cityArry.
NSString *scannedStr = @"Chennai Tnager";
NSPredicate *predicate = [NSPredicate predicateWithFormat: @"SELF in[cd] %@", [scannedStr componentsSeparatedByString:@" "]];
[cityArray filteredArrayUsingPredicate: predicate];
isSubsetOfSet in NSPredicate string
Something like this should work:
NS(Ordered)Set *smallerSet = …
request.predicate =
[NSPredicate predicateWithFormat:@"SUBQUERY(attribute, $a, $a IN %@).@count == %lu",
smallerSet, (unsigned long)[smallerSet count]];
The predicate checks if the number of "attribute" values contained in smallerSet
is
equal to the number of elements in smallerSet
. If yes, then smallerSet
must be
a subset of the "attribute" set.
A string based predicate is not generally faster than a block based (compare
https://stackoverflow.com/a/21158730/1187415). But a Core Data fetch request (with a
SQlite store file) cannot use block based predicates.
Efficient means to enumerate an array looking for items in another array
My thought would be to use a set -
-(NSArray*)getItemsWithGuids:(NSArray*)guids inAllObjects:(NSArray *)allObjects
{
NSSet *matchGuids=[NSSet setWithArray:guids];
NSMutableArray *matchingObjects=[NSMutableArray new];
for (SOmeObjectWithGuidProperty *someObject in allObjects) {
if ([matchGuids contains:someObject.guid]) {
[matchingObjects addObject:someObject];
}
}
return [matchingObjects copy];
}
find number of yes in NSMutableArray
You can use NSPredicate
NSArray *totalYes = [carBoxesArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(isDeleted == %@)", @"yes"]];
NSLog(@"Found Total YES: %d",totalYes.count);
Objective-C: How to find the most common string in an array?
Simplest way is probably NSCountedSet
:
NSCountedSet* stringSet = [[NSCountedSet alloc] initWithArray:strings];
NSString* mostCommon = nil;
NSUInteger highestCount = 0;
for(NSString* string in stringSet) {
NSUInteger count = [stringSet countForObject:string];
if(count > highestCount) {
highestCount = count;
mostCommon = string;
}
}
How to filter array based on dictionary key?
There are at least a half-dozen ways to do this. You don't say if you're using Objective-C or Swift, although the sample code you show looks like Objective-C.
If you were using Swift you could use the built-in Swift filter function, but let's forgo that.
You could use filteredArrayUsingPredicate
, as you're doing now.
You could use indexesOfObjectsPassingTest
to build an NSIndexSet
of the objects in your array that meet your criteria (That method takes a block, and for all objects where your block returns true, the resulting index set includes the index of the object. You'd then use objectsAtIndexes
to return an array of the objects listed in the index set.
I haven't benchmarked it, but I suspect that for large arrays, the predicate method is slower, since predicates are a very flexible method of selecting objects, and flexible code tends to be slower code. However, unless you are filtering tens of thousands of objects, or more, I doubt if you'd even notice the difference in performance.
Don't fall into the trap of premature optimization - wasting your time and making your code more complex to optimize things that do not have a meaningful impact on your app's performance.
Unless your app is running noticeably slowly, and you've tested it and determined that the array filtering has a significant influence on that slowness, it's probably not worth worrying about.
Related Topics
How to Use Avfoundation to Crop a Video
Xcode 7 Swift 2 Impossible to Instantiate Uiviewcontroller Subclass of Generic Uitableviewcontroller
How to Present iOS Uiactionsheet in Swift
When Should I Use the Various Storage Mechanisms in iOS
Auto-Renewable Subscription in iOS7
Xcode 5 & Asset Catalog: How to Reference the Launchimage
Detecting Whether or Not Device Support Phone Calls
Change Text of "Return" Keyboard Button
How to Do Some Stuff in Viewdidappear Only Once
Firebase Cloud Messaging - Check Existing or Available Topics
Realmswift: Convert Results to Swift Array
Uiimage Imagenamed Returns Nil
Creating Delegates on the Spot with Blocks
How to Set iOS Status Bar Background Color in React Native