好奇心から、valueForKeyPath:
単純な反復と比較してみました。OS X 10.8.2 を実行している私の iMac コア i7 では、単純な反復は 10M 要素の配列に対して約 2 倍高速です。
私が作成したテストプログラムは次のとおりです。
#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;
}
私のマシンでの結果:
$ 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
私の仮説は、反復ソリューションは、これらのデータ構造に対して可能な限り高速であるというものです。配列要素ごとに辞書検索を行う必要はありません。さらに、このカスタムメイドの反復ソリューションには、すべてのNSNumber
オブジェクトにint
値があることがわかっているという利点があります。比較のために使用isGreaterThan:
すると、処理がいくらか遅くなります (ただし、それでも よりは高速ですvalueForKeyPath:
)。汎用ライブラリ メソッドは、ほぼ確実にそのペナルティを内部的に被ります…</p>