use std::collections::btree_map::Entry;
use std::collections::BTreeMap;
pub fn misra_gries<I, V>(stream: I, k: usize) -> BTreeMap<V, usize>
where
I: IntoIterator<Item = V>,
V: Ord + Clone,
{
let mut counters = BTreeMap::new();
for i in stream {
let counters_len = counters.len();
let mut counted = false;
match counters.entry(i.clone()) {
Entry::Occupied(mut item) => {
*item.get_mut() += 1;
counted = true;
}
Entry::Vacant(slot) => {
if counters_len < k {
slot.insert(1);
counted = true;
}
}
}
if !counted {
for c in counters.values_mut() {
*c -= 1;
}
counters = counters.into_iter().filter(|&(_, v)| v != 0).collect();
}
}
counters
}
#[cfg(test)]
mod test {
use super::*;
use std::collections::BTreeMap;
pub fn exact_frequencies<I, V>(stream: I) -> BTreeMap<V, usize>
where
I: IntoIterator<Item = V>,
V: Ord + Clone,
{
let mut counts = BTreeMap::new();
for i in stream {
*counts.entry(i.clone()).or_insert(0) += 1;
}
counts
}
#[test]
fn test_exact_frequencies() {
let numbers = vec![1, 2, 1, 3, 3, 1, 2, 4];
let counts = exact_frequencies(numbers.iter());
assert_eq!(*counts.get(&1).unwrap() as u32, 3);
assert_eq!(*counts.get(&2).unwrap() as u32, 2);
assert_eq!(*counts.get(&3).unwrap() as u32, 2);
assert_eq!(*counts.get(&4).unwrap() as u32, 1);
}
quickcheck! {
fn is_exact(xs: Vec<u32>) -> bool {
exact_frequencies(xs.iter()) == misra_gries(xs.iter(), xs.len())
}
fn is_approximate(xs: Vec<u32>) -> bool {
let exacts = exact_frequencies(xs.iter());
let n = xs.len();
for k in 1..n {
let epsilon_n = n / (k+1);
let approxes = misra_gries(xs.iter(), k);
for (i, c) in approxes {
let exact = *exacts.get(i).unwrap();
if c > exact {
return false;
}
if epsilon_n < exact && c < (exact - epsilon_n) {
return false;
}
}
}
true
}
}
}