Reputation: 15669
Is there any quick and efficient way of finding max int
value in NSArray
that consists of NSDictionary
objects? I mean sure, I can implement for
cycle going through, but I am looking for some API function that's already tweaked to maximum speed since it's operating with fairly large amount of data.
[(int, string, string), (int, string, string), (int, string, string)]
I tried working with valueForKeyPath
but that really didn't help me so far, since it works with "ordinary" NSArray objects.
Upvotes: 1
Views: 2473
Reputation: 6927
Yes, There is a better way to sort an array consists of the NSDictionary
. In the given snatch of code it consists the dictionary of places. Each dictionary object consists of Name and Distance keys.
The array would be look like:
(
{ name = "Electronics Store";
distance = 9;
},{ name = "Caffeteria Store";
distance = 29;
}
)
Here the sorting is done on the basis of "key distance" of dictionary. Please make sure the key distance need to be an int value.
For example :
[detail_dict setValue:[NSNumber numberWithInt:[distance intValue]] forKey:@"distance"];
NOTE: It makes the distance as a int value for sorting.
After that just do the sorting the default method of NSMutableArray
:
CODE:
[arr_details sortUsingDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"distance" ascending:YES]]]
Upvotes: 1
Reputation: 539955
I don't know now fast this is, but you can use the built-in @max
operator with valueForKeyPath:
:
NSArray *array = @[
@{ @"value" : @5, @"name" : @"foo"},
@{ @"value" : @7, @"name" : @"bar"},
@{ @"value" : @3, @"name" : @"abc"}
];
NSNumber *maximum = [array valueForKeyPath:@"@max.value"];
NSLog(@"%@", maximum);
// Output: 7
In this example, value
is the dictionary key, and the value is a NSNumber
object, because you cannot store an int
in a dictionary.
(See Collection Operators in the "Key-Value Coding Programming Guide".)
UPDATE: This is definitely not the fastest solution, as Arkku has shown in his answer.
Upvotes: 1
Reputation: 42149
Out of curiosity, I did a little comparison of valueForKeyPath:
vs simple iteration. On my iMac core i7 running OS X 10.8.2, the simple iteration is about twice as fast for an array of 10M elements.
Here's the test program I made:
#import <Foundation/Foundation.h>
#undef NDEBUG
#import <assert.h>
#import <limits.h>
#import <stdio.h>
#import <stdlib.h>
#define ELEMENTS_IN_ARRAY 10000000
NSArray *newArrayWithDictionaryElementCount(int count) {
NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:count];
for (int i = 0; i < count; ++i) {
[arr addObject:[NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat:@"value%d", i], @"string",
[NSNumber numberWithInt:rand()], @"int",
nil]];
}
return arr;
}
int maxIntValueByKeyPathInArray(NSArray *arr) {
return [(NSNumber *)[arr valueForKeyPath:@"@max.int"] intValue];
}
int maxIntValueByIterationInArray(NSArray *arr) {
int max = INT_MIN;
for (NSDictionary *dict in arr) {
int val = [(NSNumber *)[dict valueForKey:@"int"] intValue];
if (val > max) {
max = val;
}
}
return max;
}
NSTimeInterval timeExecutionOf(void(^blockToTime)(void)) {
NSDate *start = [NSDate date];
blockToTime();
return -[start timeIntervalSinceNow];
}
int main (int argc, const char *argv[]) {
srand(time(NULL));
@autoreleasepool {
NSArray *arr = newArrayWithDictionaryElementCount(ELEMENTS_IN_ARRAY);
assert(maxIntValueByIterationInArray(arr) == maxIntValueByKeyPathInArray(arr));
(void) printf("Time by key path: %f s\n", timeExecutionOf(^{ maxIntValueByKeyPathInArray(arr); }));
(void) printf("Time by iteration: %f s\n", timeExecutionOf(^{ maxIntValueByIterationInArray(arr); }));
}
return 0;
}
The results on my machine:
$ clang -fobjc-arc -framework Foundation -O4 -march=corei7 -o arraytest arraytest.m
$ ./arraytest
Time by key path: 1.809646 s
Time by iteration: 0.886023 s
My hypothesis is that the iterative solution is already about as fast as can be for these data structures; there is no getting around having to do the dictionary look-up for each array element. Furthermore, this custom-made iterative solution benefits from knowing that all the NSNumber
objects have int
values; using isGreaterThan:
for comparison slows things down somewhat (but it's still faster than valueForKeyPath:
). Any general-purpose library method would almost certainly incur that penalty internally…
Upvotes: 4