use core::ops::Range;
pub fn balance<T>(s: &[T], x: f64, quantify: &mut impl FnMut(&T) -> f64) -> i64 {
let mut above = 0_i64;
let mut below = 0_i64;
for si in s {
let sif = quantify(si);
if sif > x {
above += 1;
} else if sif < x {
below += 1;
};
}
if below == above {
return 0;
};
let diff = (above - below).abs();
if diff < (s.len() as i64 - above - below) {
return 0;
};
1
}
pub fn fpart(s: &mut [f64], rng: &Range<usize>, pivot: f64) -> usize {
let mut ltsub = rng.start;
let mut gtsub = rng.end - 1;
loop {
while s[ltsub] <= pivot {
ltsub += 1;
if ltsub > gtsub {
return ltsub;
};
}
while s[gtsub] >= pivot {
gtsub -= 1;
if gtsub <= ltsub {
return ltsub;
};
}
s.swap(ltsub, gtsub);
}
}
fn fmin(s: &[f64], rng: Range<usize>) -> f64 {
let mut min = s[rng.start];
for &si in s.iter().take(rng.end).skip(rng.start + 1) {
if si < min {
min = si;
};
}
min
}
fn fmin2(s: &[f64], rng: Range<usize>) -> f64 {
let mut min1 = s[rng.start];
let mut min2 = min1;
for &si in s.iter().take(rng.end).skip(rng.start + 1) {
if si < min1 {
min2 = min1;
min1 = si;
} else if si < min2 {
min2 = si;
}
}
(min1 + min2) / 2.0
}
fn fmax(s: &[f64], rng: Range<usize>) -> f64 {
let mut max = s[rng.start];
for &si in s.iter().take(rng.end).skip(rng.start + 1) {
if si > max {
max = si;
};
}
max
}
pub fn auto_median<T>(set: &[T], quantify: &mut impl FnMut(&T) -> f64) -> f64 {
let n = set.len();
let mut pivot = 0_f64;
let fset = set
.iter()
.map(|tval| {
let fval = quantify(tval);
pivot += fval;
fval
})
.collect::<Vec<f64>>();
pivot /= n as f64; if (n & 1) == 1 {
med_odd(fset, 0..n, pivot)
} else {
med_even(fset, 0..n, pivot)
}
}
fn med_odd(mut set: Vec<f64>, mut rng: Range<usize>, mut pivot: f64) -> f64 {
let need = rng.len() / 2; loop {
let gtsub = fpart(&mut set, &rng, pivot);
if need < gtsub {
rng.end = gtsub;
if need + 1 == gtsub {
return fmax(&set, rng.start..gtsub);
};
} else {
rng.start = gtsub;
if need == gtsub {
return fmin(&set, gtsub..rng.end);
};
};
let newpivot = set.iter().take(rng.end).skip(rng.start).sum::<f64>() / rng.len() as f64;
if newpivot == pivot {
return pivot;
}
else {
pivot = newpivot;
};
}
}
pub fn med_even(mut set: Vec<f64>, mut rng: Range<usize>, mut pivot: f64) -> f64 {
let need = rng.len() / 2 - 1;
loop {
let gtsub = fpart(&mut set, &rng, pivot);
if need < gtsub {
if need + 1 == gtsub {
return (fmax(&set, rng.start..gtsub) + fmin(&set, gtsub..rng.end)) / 2.;
};
rng.end = gtsub;
} else {
if need == gtsub {
fmin2(&set, gtsub..rng.end);
}
rng.start = gtsub;
};
let newpivot = set.iter().take(rng.end).skip(rng.start).sum::<f64>() / rng.len() as f64;
if newpivot == pivot {
return pivot;
}
else {
pivot = newpivot;
};
}
}