同じクラスのカスタム オブジェクトのコレクションのプロパティの最大値を取得する必要があります。オブジェクトは NSArray に格納され、プロパティはたまたま数値の別の NSArray になります。
詳しく説明しましょう:
NSArray *samples; // of CMData, 4000 elements
CMData は、異なる値を持つことができる一連の異なるチャネルの特定の瞬間のサンプルをモデル化するクラスです。
@interface CMData : NSObject
@property (nonatomic) NSUInteger timeStamp;
@property (nonatomic, strong) NSArray *analogChannelData; // of NSNumber, 128 elements
@end
(質問に関係のないクラスの他のプロパティを削除しました)
たとえば、sample[1970] は次のようになります。
sample.timeStamp = 970800
sample.analogChannelData = <NSArray>
[
[0] = @(153.27)
[1] = @(345.35)
[2] = @(701.02)
...
[127] = @(-234.45)
]
ここで、analogChannelData の各要素 [i] は、timeStamp 970800 の特定のチャネル i の値を表します。
ここで、チャネル 31 の 4000 サンプルすべての最大値を取得したいと考えています。次のコードを使用します。
NSUInteger channelIndex = 31;
NSMutableArray *values = [[NSMutableArray alloc] init]; // of NSNumber
// iterate the array of samples and for each one obtain the value for a
// specific channel and store the value in a new array
for (CMData *sample in samples) {
[values addObject:sample.analogChannelData[channelIndex]];
}
// the maximum
NSNumber *maxValue = [values valueForKeyPath:@"@max.self"];
このプログラミング構造を NSPredcicate を介したフィルターで置き換えるか、valueForKeyPath: を使用して、必要なデータを最大限に取得したいと考えています。
forループなしでこれを行う方法を知っている人はいますか? NSPredicates や valueForKeyPath を使用しているだけですか?
よろしくお願いいたします。
更新 1
最後に、for ループ バージョンを keyPath バージョンに対してベンチマークしました (受け入れられた回答を参照)。はるかに高速に実行されるため、for ループを使用することをお勧めします。アルゴリズムのクラスで学んだいくつかの教訓を思い出して、値を格納するための配列を必要としないさらに高速なバージョンを実装しました。選択したチャネルを反復処理し、各反復で最大値を選択するだけです。これは断然最速のバージョンです。
そう:
- バージョン 1: for ループ (上記のコードを参照)
- バージョン 2: カスタム プロパティを含むバージョン (Marcus からの選択された回答、更新 2 を参照)
- バージョン 3: 新しいコード
バージョン 3 のコード:
NSUInteger channelIndex = 31;
NSNumber *maxValue = @(-INFINITY);
for (CMTData *sample in samples) {
NSNumber *value = sample.analogChannelData[channelIndex];
if (value) { // I allow the possibility of NSNull values in the NSArray
if ([value compare:maxValue] == NSOrderedDescending)
maxValue = value;
}
}
// the maximum is in maxValue at the end of the loop
パフォーマンス:
iOS シミュレーターでの 20.000 回の反復後:
- バージョン 1: 12.2722 秒。
- バージョン 2: 21.0149 秒。
- バージョン 3: 5.6501 秒。
決定は明らかです。3 番目のバージョンを使用します。
更新 2
さらに調査した結果、KVC が内部配列の個々の要素に対して機能しないことが明らかになりました。次のリンクを参照してください: NSArrays の NSArrays を使用した KVCおよびTo-Many プロパティのコレクション アクセサー パターン
とにかく、要素の最大値を計算したかったので、KVC を機能させるためにいくつかのトリックを使用するよりも、配列を反復処理する方が適切です。