From c64544baa870fde8ab9ab3d6add43978bfde09db Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Tue, 6 Mar 2018 17:04:39 +0100 Subject: [PATCH] Implement iteration of histograms --- src/histogram.rs | 38 ++++++++++++++++++++++++++++++++++++++ tests/histogram.rs | 15 +++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/histogram.rs b/src/histogram.rs index 17cef76..deaaf45 100644 --- a/src/histogram.rs +++ b/src/histogram.rs @@ -105,6 +105,44 @@ macro_rules! define_histogram { pub fn ranges(&self) -> &[f64] { &self.range as &[f64] } + + /// Return an iterator over the bins and corresponding ranges: + /// `((lower, upper), count)` + #[inline] + pub fn iter(&self) -> IterHistogram { + self.into_iter() + } + } + + /// Iterate over all `(range, count)` pairs in the histogram. + pub struct IterHistogram<'a> { + remaining_bin: &'a [u64], + remaining_range: &'a [f64], + } + + impl<'a> ::core::iter::Iterator for IterHistogram<'a> { + type Item = ((f64, f64), u64); + fn next(&mut self) -> Option<((f64, f64), u64)> { + if let Some((&bin, rest)) = self.remaining_bin.split_first() { + let left = self.remaining_range[0]; + let right = self.remaining_range[1]; + self.remaining_bin = rest; + self.remaining_range = &self.remaining_range[1..]; + return Some(((left, right), bin)); + } + None + } + } + + impl<'a> ::core::iter::IntoIterator for &'a $name { + type Item = ((f64, f64), u64); + type IntoIter = IterHistogram<'a>; + fn into_iter(self) -> IterHistogram<'a> { + IterHistogram { + remaining_bin: self.bins(), + remaining_range: self.ranges(), + } + } } impl $crate::Histogram for $name { diff --git a/tests/histogram.rs b/tests/histogram.rs index b6b8ddb..fc641ad 100644 --- a/tests/histogram.rs +++ b/tests/histogram.rs @@ -27,6 +27,21 @@ fn from_ranges() { assert_eq!(h.bins(), &[1, 0, 0, 0, 0, 0, 1, 0, 0, 2]); } +#[test] +fn iter() { + let mut h = Histogram10::from_ranges( + [0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.7, 0.8, 0.9, 1.0, 2.0].iter().cloned()).unwrap(); + for &i in &[0.05, 0.7, 1.0, 1.5] { + h.add(i).unwrap(); + } + let iterated: Vec<((f64, f64), u64)> = h.iter().collect(); + assert_eq!(&iterated, &[ + ((0., 0.1), 1), ((0.1, 0.2), 0), ((0.2, 0.3), 0), ((0.3, 0.4), 0), + ((0.4, 0.5), 0), ((0.5, 0.7), 0), ((0.7, 0.8), 1), ((0.8, 0.9), 0), + ((0.9, 1.0), 0), ((1.0, 2.0), 2) + ]); +} + #[test] fn from_ranges_infinity() { let inf = std::f64::INFINITY;