Skip to main content

distr_combinators/
histogram.rs

1use indexmap::IndexMap;
2
3/// A convenience to analyze the distribution of generated values
4#[derive(Debug)]
5pub struct Histogram<T: std::cmp::Eq + std::hash::Hash> {
6  pub lookup: IndexMap<T, usize>
7}
8impl <T: std::cmp::Eq + std::hash::Hash> FromIterator<T> for Histogram<T> {
9  fn from_iter<I: IntoIterator<Item=T>>(iter: I) -> Self {
10    let mut lookup = IndexMap::new();
11    for t in iter {
12      *lookup.entry(t).or_insert(0) += 1;
13    }
14    // Sort by count (ascending)
15    lookup.sort_by(|_, v1, _, v2| v1.cmp(v2));
16    Histogram { lookup }
17  }
18}
19
20impl <T: std::cmp::Eq + std::hash::Hash> Histogram<T> {
21  pub fn from(iter: impl IntoIterator<Item=T>) -> Self {
22    Self::from_iter(iter)
23  }
24
25  /// Returns an iterator over the histogram entries, sorted by occurrence count in ascending order.
26  pub fn iter(&self) -> impl Iterator<Item = (&T, usize)> {
27    self.lookup.iter().map(|(k, v)| (k, *v))
28  }
29}
30
31impl<'a, T: std::cmp::Eq + std::hash::Hash> IntoIterator for &'a Histogram<T> {
32  type Item = (&'a T, usize);
33  type IntoIter = std::iter::Map<indexmap::map::Iter<'a, T, usize>, fn((&'a T, &'a usize)) -> (&'a T, usize)>;
34
35  fn into_iter(self) -> Self::IntoIter {
36    self.lookup.iter().map(|(k, v)| (k, *v))
37  }
38}
39
40impl<T: std::cmp::Eq + std::hash::Hash> IntoIterator for Histogram<T> {
41  type Item = (T, usize);
42  type IntoIter = indexmap::map::IntoIter<T, usize>;
43
44  fn into_iter(self) -> Self::IntoIter {
45    self.lookup.into_iter()
46  }
47}