use core::ops::Range;
pub fn quant_vec<T, U>(v: &[T], quantify: impl Fn(&T) -> U) -> Vec<U> {
v.iter().map(quantify).collect::<Vec<U>>()
}
pub fn balance<T>(s: &[T], x: f64, quantify: impl Fn(&T) -> f64) -> i64 {
let mut bal = 0_i64;
let mut eq = 0_i64;
for si in s {
let sif = quantify(si);
if sif > x {
bal += 1;
} else if sif < x {
bal -= 1;
} else {
eq += 1;
};
}
if bal == 0 {
return 0;
};
if bal.abs() <= eq {
return 0;
};
1
}
pub fn midof3<'a, T>(item1: &'a T, item2: &'a T, item3: &'a T) -> &'a T
where
T: PartialOrd,
{
let (min, max) = if *item1 <= *item2 {
(item1, item2)
} else {
(item2, item1)
};
if *item3 <= *min {
return min;
};
if *item3 <= *max {
return item3;
};
max
}
pub fn part<T>(s: &mut [&T], rng: &Range<usize>, pivot: &T) -> (usize, usize, usize)
where
T: PartialOrd,
{
let mut startsub = rng.start;
let mut gtsub = startsub;
let mut ltsub = rng.end - 1;
let mut endsub = rng.end - 1;
loop {
while s[gtsub] > pivot {
if gtsub == ltsub {
return (startsub, 1 + gtsub, 1 + endsub);
};
gtsub += 1;
}
if s[gtsub] == pivot {
if gtsub > startsub {
s[gtsub] = s[startsub];
};
if gtsub == ltsub {
return (1 + startsub, 1 + gtsub, 1 + endsub);
};
startsub += 1;
gtsub += 1;
continue;
};
'lt: loop {
if s[ltsub] < pivot {
ltsub -= 1;
if gtsub >= ltsub {
return (startsub, gtsub, 1 + endsub);
};
continue 'lt;
}
if s[ltsub] == pivot {
if ltsub < endsub {
s[ltsub] = s[endsub];
};
ltsub -= 1;
if gtsub >= ltsub {
return (startsub, gtsub, endsub);
};
endsub -= 1;
continue 'lt;
};
break 'lt;
}
s.swap(ltsub, gtsub);
gtsub += 1;
ltsub -= 1;
if gtsub > ltsub {
return (startsub, gtsub, 1 + endsub);
};
}
}
fn min<'a, T>(s: &[&'a T], rng: Range<usize>) -> &'a T
where
T: PartialOrd,
{
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 max<'a, T>(s: &[&'a T], rng: Range<usize>) -> &'a T
where
T: PartialOrd,
{
let mut max = &s[rng.start];
for si in s.iter().take(rng.end).skip(rng.start + 1) {
if *si > *max {
max = si;
};
}
max
}
fn min2<'a, T>(s: &[&'a T], rng: Range<usize>) -> (&'a T, &'a T)
where
T: PartialOrd,
{
let (mut min1, mut min2) = if s[rng.start + 1] < s[rng.start] {
(&s[rng.start + 1], &s[rng.start])
} else {
(&s[rng.start], &s[rng.start + 1])
};
for si in s.iter().take(rng.end).skip(rng.start + 2) {
if *si < *min1 {
min2 = min1;
min1 = si;
} else if *si < *min2 {
min2 = si;
}
}
(min1, min2)
}
fn max2<'a, T>(s: &[&'a T], rng: Range<usize>) -> (&'a T, &'a T)
where
T: PartialOrd,
{
let (mut max1, mut max2) = if s[rng.start + 1] > s[rng.start] {
(&s[rng.start + 1], &s[rng.start])
} else {
(&s[rng.start], &s[rng.start + 1])
};
for si in s.iter().take(rng.end).skip(rng.start + 2) {
if *si > *max1 {
max2 = max1;
max1 = si;
} else if *si > *max2 {
max2 = si;
}
}
(max2, max1)
}
pub fn med_odd<T>(set: &[T]) -> &T
where
T: PartialOrd,
{
let mut rng = 0..set.len();
let mut need = set.len() / 2; let mut s: Vec<&T> = set.iter().collect();
loop {
let pivot = midof3(s[rng.start],s[(rng.start+rng.end)/2],s[rng.end-1]);
let (gtsub, ltsub, ltend) = part(&mut s, &rng, pivot);
if need + ltsub - rng.start + 2 < ltend {
need += ltsub - rng.start;
rng.start = ltsub;
rng.end = ltend;
continue;
}
if need + ltsub - rng.start < rng.end {
need += ltsub - rng.start;
if need + 2 == ltend {
return max2(&s, ltsub..ltend).0;
};
if need + 1 == ltend {
return max(&s, ltsub..ltend);
};
return pivot;
};
need -= rng.end - ltsub;
if need > gtsub+1 {
rng.start = gtsub;
rng.end = ltsub;
continue;
}
if need < gtsub {
return pivot;
};
if need == gtsub {
return min(&s, gtsub..ltsub);
};
return min2(&s, gtsub..ltsub).1;
}
}
pub fn med_even<T:PartialOrd>(set: &[T]) -> (&T, &T) {
let mut rng = 0..set.len();
let mut need = set.len() / 2 - 1; let mut s: Vec<&T> = set.iter().collect();
loop {
let pivot = midof3(s[rng.start], s[(rng.start + rng.end) / 2], s[rng.end - 1]);
let (gtsub, ltsub, ltend) = part(&mut s, &rng, pivot);
if need + ltsub - rng.start + 2 < ltend {
need += ltsub - rng.start;
rng.start = ltsub;
rng.end = ltend;
continue;
};
if need + ltsub - rng.start < rng.end {
need += ltsub - rng.start;
if need + 2 == ltend {
return max2(&s, ltsub..ltend);
};
if need + 1 == ltend {
return (max(&s, ltsub..ltend), pivot);
};
let eqend = rng.end-1+gtsub-rng.start;
if need < eqend { return (pivot,pivot); };
if need == eqend {
if gtsub > rng.start { return (pivot,pivot); }
else { return (pivot,min(&s, gtsub..ltsub)); }
};
};
need -= rng.end - ltsub;
if need+1 > gtsub {
rng.start = gtsub;
rng.end = ltsub;
continue;
};
if need+1 < gtsub {
return (pivot,pivot);
};
if need+1 == gtsub {
return (pivot, min(&s, gtsub..ltsub));
};
if need == gtsub {
return min2(&s, gtsub..ltsub);
};
}
}