49

NSArrayに含まNSNumbersれるすべての値を比較しfloatsて最大のものと最小のものを見つける効果的で優れた方法は何ですか?

Objective-Cでこれをすばやくすばやく行う方法はありますか?

4

5 に答える 5

146

実行速度(プログラミング速度ではなく) が重要な場合は、明示的なループが最も高速です。1000000 個の乱数の配列を使用して、次のテストを行いました。

バージョン 1: 配列を並べ替える:

NSArray *sorted1 = [numbers sortedArrayUsingSelector:@selector(compare:)];
// 1.585 seconds

バージョン 2: 「doubleValue」を使用したキー値コーディング:

NSNumber *max=[numbers valueForKeyPath:@"@max.doubleValue"];
NSNumber *min=[numbers valueForKeyPath:@"@min.doubleValue"];
// 0.778 seconds

バージョン 3: 「self」を使用したキー値コーディング:

NSNumber *max=[numbers valueForKeyPath:@"@max.self"];
NSNumber *min=[numbers valueForKeyPath:@"@min.self"];
// 0.390 seconds

バージョン 4: 明示的なループ:

float xmax = -MAXFLOAT;
float xmin = MAXFLOAT;
for (NSNumber *num in numbers) {
    float x = num.floatValue;
    if (x < xmin) xmin = x;
    if (x > xmax) xmax = x;
}
// 0.019 seconds

バージョン 5: ブロック列挙:

__block float xmax = -MAXFLOAT;
__block float xmin = MAXFLOAT;
[numbers enumerateObjectsUsingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop) {
    float x = num.floatValue;
    if (x < xmin) xmin = x;
    if (x > xmax) xmax = x;
}];
// 0.024 seconds

テスト プログラムは、1000000 個の乱数の配列を作成し、すべての並べ替え手法を同じ配列に適用します。上記のタイミングは 1 回の実行の出力ですが、約 20 回実行し、各実行で非常に類似した結果が得られます。また、キャッシュ効果を除外するために、5 つの並べ替え方法が適用される順序を変更しました。

更新: (できれば) より優れたテスト プログラムを作成しました。完全なソース コードはhttps://gist.github.com/anonymous/5356982にあります。1000000 個の乱数の配列をソートする平均時間は次のとおりです (秒単位、3.1 GHz Core i5 iMac、リリース コンパイル)。

並べ替え 1.404
KVO1 1.087
KVO2 0.367
高速列挙 0.017
ブロック列挙 0.021

更新 2:ご覧のとおり、高速列挙はブロック列挙よりも高速です (これは、http: //blog.bignerdranch.com/2337-incremental-arrayification/にも記載されています)。

編集:以下は完全に間違っています。Hot Licks が正しく認識したように、ロックとして使用されるオブジェクトを初期化するのを忘れたため、同期がまったく行われないためです。またlock = [[NSObject alloc] init];、同時列挙は非常に遅いため 、あえて結果を表示しません。おそらく、より高速な同期メカニズムが役立つかもしれません...)

NSEnumerationConcurrentオプションをブロック列挙に 追加すると、これは劇的に変化します。

__block float xmax = -MAXFLOAT;
__block float xmin = MAXFLOAT;
id lock;
[numbers enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop) {
    float x = num.floatValue;
    @synchronized(lock) {
        if (x < xmin) xmin = x;
        if (x > xmax) xmax = x;
    }
}];

ここでのタイミングは

同時列挙型 0.009

したがって、高速列挙の約 2 倍の速さです。結果は、使用可能なスレッドの数に依存するため、おそらく代表的なものではありません。でもとにかく面白い!「最も使いやすい」同期方法を使用したことに注意してください。これは、最速ではない可能性があります。

于 2013-04-10T16:43:46.667 に答える
14

NSNumber の下にラップして float を保存し、次に

NSNumber *max=[numberArray valueForKeyPath:@"@max.doubleValue"];
NSNumber *min=[numberArray valueForKeyPath:@"@min.doubleValue"];

*コンパイルおよびチェックされていない、intValue でチェック済み、double か float か不明

于 2013-04-10T16:20:49.720 に答える
2

それを並べ替えます。最初と最後の要素を取ります。

ところで:フロートを NSArray に格納することはできません。それらを NSNumber オブジェクトでラップする必要があります。

NSArray *numbers = @[@2.1, @8.1, @5.0, @.3];
numbers = [numbers sortedArrayUsingSelector:@selector(compare:)];

float min = [numbers[0] floatValue];
float max = [[numbers lastObject] floatValue];
于 2013-04-10T16:15:15.930 に答える