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