(values: &mut [f64])
| 22 | } |
| 23 | |
| 24 | fn compute_box_stats(values: &mut [f64]) -> BoxStats { |
| 25 | values.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)); |
| 26 | let q1 = percentile(values, 25.0); |
| 27 | let median = percentile(values, 50.0); |
| 28 | let q3 = percentile(values, 75.0); |
| 29 | let iqr = q3 - q1; |
| 30 | let lo_fence = q1 - 1.5 * iqr; |
| 31 | let hi_fence = q3 + 1.5 * iqr; |
| 32 | let whisker_lo = values |
| 33 | .iter() |
| 34 | .copied() |
| 35 | .filter(|&v| v >= lo_fence) |
| 36 | .fold(f64::INFINITY, f64::min); |
| 37 | let whisker_hi = values |
| 38 | .iter() |
| 39 | .copied() |
| 40 | .filter(|&v| v <= hi_fence) |
| 41 | .fold(f64::NEG_INFINITY, f64::max); |
| 42 | let outliers: Vec<f64> = values |
| 43 | .iter() |
| 44 | .copied() |
| 45 | .filter(|&v| v < lo_fence || v > hi_fence) |
| 46 | .collect(); |
| 47 | BoxStats { |
| 48 | q1, |
| 49 | median, |
| 50 | q3, |
| 51 | whisker_lo, |
| 52 | whisker_hi, |
| 53 | outliers, |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | fn percentile(sorted: &[f64], p: f64) -> f64 { |
| 58 | if sorted.is_empty() { |
no test coverage detected