linq - C# Method on one array (values) conditional on a second array (dates) -
i compute average or sum or method on elements in array of values(doubles) conditional on second array same length.
for instance, have sorted array dates (double[]dts) , compute average between start date (std) , end date (edd) on value array (double[]vals) (which simple , code below does).
but if want compute e.g. average of mondays in year code below doesnt work more. ideas? thanks!
public static double aggr(double[] dts, double[] vals, double std, double edd) { int stdindex = 0; int eddindex = dts.length; (int k = 0; k < dts.length; k++) { if (dts[k] == std) { stdindex = k; } if (dts[k] == edd) { eddindex = k; } } return vals.skip(stdindex).take(eddindex-stdindex).average(); }
thanks everybody. think answers work. here new code:
public static double aggr(double[] dts, double[] vals, double std, double edd, string peakoffpeakbase, double sumavg) { double result; if (sumavg == 1) { if (peakoffpeakbase=="peak") { result = dts.zip(vals, (d, v) => new { d, v }) .where(dv => (dv.d >= std & dv.d < edd & datetime.fromoadate(dv.d).dayofweek != dayofweek.saturday & datetime.fromoadate(dv.d).dayofweek != dayofweek.sunday & datetime.fromoadate(dv.d).hour > 7 & datetime.fromoadate(dv.d).hour < 20)) .select(dv => dv.v).sum(); } else if (peakoffpeakbase=="offpeak") { result = dts.zip(vals, (d, v) => new { d, v }) .where(dv => (dv.d >= std & dv.d < edd & datetime.fromoadate(dv.d).dayofweek == dayofweek.saturday | datetime.fromoadate(dv.d).dayofweek == dayofweek.sunday | datetime.fromoadate(dv.d).hour < 8 | datetime.fromoadate(dv.d).hour > 19)) .select(dv => dv.v).sum(); } else { result = dts.zip(vals, (d, v) => new { d, v }) .where(dv => (dv.d >= std && dv.d < edd)) .select(dv => dv.v).sum(); } } else { if (peakoffpeakbase == "peak") { result = dts.zip(vals, (d, v) => new { d, v }) .where(dv => (dv.d >= std & dv.d < edd & datetime.fromoadate(dv.d).dayofweek != dayofweek.saturday & datetime.fromoadate(dv.d).dayofweek != dayofweek.sunday & datetime.fromoadate(dv.d).hour > 7 & datetime.fromoadate(dv.d).hour < 20)) .select(dv => dv.v).average(); } else if (peakoffpeakbase == "offpeak") { result = dts.zip(vals, (d, v) => new { d, v }) .where(dv => (dv.d >= std & dv.d < edd & (datetime.fromoadate(dv.d).dayofweek == dayofweek.saturday | datetime.fromoadate(dv.d).dayofweek == dayofweek.sunday | datetime.fromoadate(dv.d).hour < 8 | datetime.fromoadate(dv.d).hour > 19))) .select(dv => dv.v).average(); } else { result = dts.zip(vals, (d, v) => new { d, v }) .where(dv => (dv.d >= std && dv.d < edd)) .select(dv => dv.v).average(); } } return result; }
obviously terrible , verbose. combine answers below , write sth like:
result = dts.zip(vals, (d, v) => new { d, v }) .where(dv => (dv.d.intimerange(std,edd).isbusinesshour(peakoffpeakbase)) .select(dv => dv.v).customx(indicator);
where intimerange , isbusinesshour extension methods described below , customx take argument , either average, sum or sth else. cant work. again!
you can use zip
combine 2 arrays:
double result = dts.zip(vals, (d,v) => new { d, v}) .where( dv => somecondition(dv.d)) .select( dv => dv.v).average();
this calculates average of vals
values, predicate somecondition
returns true
corresponding dts
value.
Comments
Post a Comment