use crate::utilities::Classification;
use crate::utilities::{breaks_to_classification, to_vec_f64};
use num_traits::ToPrimitive;
pub fn get_head_tail_classification<T: ToPrimitive>(data: &[T]) -> Classification {
let breaks: Vec<f64> = get_head_tail_breaks(data);
breaks_to_classification(&breaks, data)
}
pub fn get_head_tail_breaks<T: ToPrimitive>(data: &[T]) -> Vec<f64> {
let data = to_vec_f64(data);
let mut breaks: Vec<f64> = vec![];
let mut sorted_data: Vec<f64> = vec![];
for item in data.iter().take(data.len()) {
sorted_data.push(*item);
}
sorted_data.sort_by(|a, b| a.partial_cmp(b).unwrap());
head_tail_recursion(&sorted_data, &mut breaks);
breaks
}
pub fn head_tail_recursion(data: &Vec<f64>, breaks: &mut Vec<f64>) {
let mut mean: f64 = 0.0;
for val in data {
mean += val
}
mean /= data.len() as f64;
breaks.push(mean);
let mut low = 0;
let mut high = data.len();
let mut break_idx = 'outer: loop {
let mid = (low + high) / 2;
if mean < data[mid] as f64 {
high = mid;
} else if mean == data[mid] {
break 'outer mid;
} else if high - low <= 1 {
break 'outer high;
} else {
low = mid;
}
};
while break_idx != 0 && data[break_idx] == data[break_idx - 1] {
break_idx -= 1;
}
let head: Vec<f64> = data[break_idx..].to_vec();
if !head.is_empty()
&& (head.len() as f64) / (data.len() as f64) <= 0.4
&& head[0] != head[head.len() - 1]
{
head_tail_recursion(&head, breaks);
}
}