use indxvec::{here, Vecops};
pub fn balance<T>(s: &[T], x: f64) -> i64
where
T: Copy,
f64: From<T>,
{
let mut above = 0_i64;
let mut below = 0_i64;
for &si in s {
let sif = f64::from(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 naive_median<T>(s: &[T]) -> f64
where
T: Copy + PartialOrd,
f64: From<T>,
{
let n = s.len();
if n == 0 {
panic!("{} empty vector!", here!());
};
if n == 1 {
return f64::from(s[0]);
};
if n == 2 {
return (f64::from(s[0]) + f64::from(s[1])) / 2.0;
};
let mut sf = s.to_vec(); sf.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
let mid = s.len() / 2; if (n & 1) == 0 {
(f64::from(sf[mid - 1]) + f64::from(sf[mid])) / 2.0
} else {
f64::from(sf[mid])
} }
fn part<T>(s: &[T], pivot: f64) -> (Vec<T>, Vec<T>)
where
T: Copy,
f64: From<T>,
{
let mut ltset = Vec::new();
let mut gtset = Vec::new();
for &f in s {
if f64::from(f) < pivot {
ltset.push(f);
} else {
gtset.push(f);
};
}
(ltset, gtset)
}
pub fn r_median<T>(set: &[T]) -> f64
where
T: Copy + PartialOrd,
f64: From<T>,
{
let n = set.len();
let (min, max) = set.minmaxt();
let pivot = (f64::from(min) + f64::from(max)) / 2.;
if (n & 1) == 0 {
r_med_even(set, n / 2, pivot, f64::from(min), f64::from(max))
} else {
r_med_odd(set, n / 2 + 1, pivot, f64::from(min), f64::from(max))
}
}
fn r_med_odd<T>(set: &[T], need: usize, pivot: f64, setmin: f64, setmax: f64) -> f64
where
T: PartialOrd + Copy,
f64: From<T>,
{
if need == 1 {
return setmin;
};
let n = set.len();
if need == n {
return setmax;
};
let (ltset, gtset) = part(set, pivot);
let ltlen = ltset.len();
let gtlen = gtset.len();
match need {
1 => f64::from(ltset.mint()),
x if x < ltlen => {
let max = f64::from(ltset.maxt());
if setmin == max {
return f64::from(ltset[0]);
}; let newpivot = setmin + (need as f64) * (max - setmin) / (ltlen as f64);
r_med_odd(<set, need, newpivot, setmin, max)
}
x if x == ltlen => f64::from(ltset.maxt()),
x if x == ltlen + 1 => f64::from(gtset.mint()),
x if x == n => f64::from(gtset.maxt()),
_ => {
let newneed = need - ltlen;
let min = f64::from(gtset.mint());
if min == setmax {
return f64::from(gtset[0]);
}; let newpivot = min + (setmax - min) * (newneed as f64) / (gtlen as f64);
r_med_odd(>set, newneed, newpivot, min, setmax)
}
}
}
fn r_med_even<T>(set: &[T], need: usize, pivot: f64, setmin: f64, setmax: f64) -> f64
where
T: PartialOrd + Copy,
f64: From<T>,
{
let n = set.len();
let (ltset, gtset) = part(set, pivot);
let ltlen = ltset.len();
let gtlen = gtset.len();
match need {
x if x < ltlen => {
let max = f64::from(ltset.maxt());
if setmin == max {
return f64::from(ltset[0]);
}; let newpivot = setmin + (need as f64) * (max - setmin) / (ltlen as f64);
r_med_even(<set, need, newpivot, setmin, max)
}
x if x == ltlen => (f64::from(ltset.maxt()) + f64::from(gtset.mint())) / 2., x if x == n => f64::from(gtset.maxt()),
_ => {
let newneed = need - ltlen;
let min = f64::from(gtset.mint());
if min == setmax {
return f64::from(gtset[0]);
}; let newpivot = min + (newneed as f64) * (setmax - min) / (gtlen as f64);
r_med_even(>set, newneed, newpivot, min, setmax)
}
}
}