ios - Nested NSArray filtering -
i have need obtain maximum value of property of collection of custom objects of same class. objects stored in nsarray, , property happens nsarray of numbers.
let me explain in detail:
nsarray *samples; // of cmdata, 4000 elements   cmdata class models sample, specific moment in time, of set of different channels can have different values.
@interface cmdata : nsobject @property (nonatomic) nsuinteger timestamp; @property (nonatomic, strong) nsarray *analogchanneldata; // of nsnumber, 128 elements @end   (i have stripped other properties of class not relevant question)
so example, sample[1970] be:
sample.timestamp = 970800 sample.analogchanneldata = <nsarray>     [     [0] = @(153.27)     [1] = @(345.35)     [2] = @(701.02)     ...     [127] = @(-234.45)     ]   where each element [i] in analogchanneldata represents value of specific channel timestamp 970800
now want obtain maximum value 4000 samples channel 31. use following code:
nsuinteger channelindex = 31; nsmutablearray *values = [[nsmutablearray alloc] init]; // of nsnumber // iterate array of samples , each 1 obtain value  // specific channel , store value in new array (cmdata *sample in samples) {     [values addobject:sample.analogchanneldata[channelindex]]; } // maximum  nsnumber *maxvalue = [values valueforkeypath:@"@max.self"];   i want replace programming structure filter through nspredcicate or use valueforkeypath: obtain maximum of data need.
anyone knows how without loop? using nspredicates and/or valueforkeypath?
thank in advance help.
update 1
finally benckmarked for-loop version against keypath version (see accepted answer) , runs faster better go loop. recalling lessons algorithms classes, implemented faster version doesn't need array store values. iterate on selected channel , choose maximum in each iteration. far fastest version.
so:
- version 1: loop (see code above)
 - version 2: version custom property (see selected answer marcus, update 2)
 - version 3: new code
 
code version 3:
nsuinteger channelindex = 31; nsnumber *maxvalue = @(-infinity); (cmtdata *sample in samples) {     nsnumber *value = sample.analogchanneldata[channelindex];     if (value) { // allow possibility of nsnull values in nsarray         if ([value compare:maxvalue] == nsordereddescending)             maxvalue = value;     } } // maximum in maxvalue @ end of loop   performance:
after 20.000 iterations in ios simulator:
- version 1: 12.2722 sec.
 - version 2: 21.0149 sec.
 - version 3: 5.6501 sec.
 
the decision clear. i'll use third version.
update 2
after more research, clear me kvc not work infividual elements in inner array. see following links: kvc nsarrays of nsarrays , collection accessor patterns to-many properties
anyway because wanted compute maximum of elements better iterate array use tricks make kvc work.
you can solve using key value coding , collection operators.
nsnumber *result = [sample valueforkeypath:@"@max.analogdatachannel"];   update 1
as arcanfel mentioned, can join arrays together:
nsnumber *result = [samples valueforkeypath:@"@max.@unionofarrays.@analogchanneldata"];   i suggest reading documentation both linked to. there powerful features in there.
update 2
further hrd's answer, has solution, need combine changes kvc.
add propert cmdata object currentchannel. can call
[samples setvalue:@(channelindex) forkey:@"currentchannel"];   which set in every instance in array. call:
[samples valueforkeypath:@"@max.analogdataforcurrentchannel"];   then done.
Comments
Post a Comment