sfs_core/spectrum/
iter.rs

1//! Spectrum iterators.
2//!
3//! The types in this module are constructed via methods on [`Spectrum`],
4//! and generally expose no functionality other than being iterable.
5
6use std::iter::FusedIterator;
7
8use crate::array::iter::IndicesIter;
9
10use super::{Spectrum, State};
11
12/// An iterator over the allele frequencies corresponding to the indices of a [`Spectrum`].
13///
14/// See [`Spectrum::iter_frequencies`] for details.
15#[derive(Debug)]
16pub struct FrequenciesIter<'a> {
17    inner: IndicesIter<'a>,
18}
19
20impl<'a> FrequenciesIter<'a> {
21    pub(super) fn new<S: State>(spectrum: &'a Spectrum<S>) -> Self {
22        Self {
23            inner: spectrum.array.iter_indices(),
24        }
25    }
26}
27
28impl<'a> Iterator for FrequenciesIter<'a> {
29    type Item = Vec<f64>;
30
31    fn next(&mut self) -> Option<Self::Item> {
32        self.inner.next().map(|indices| {
33            indices
34                .iter()
35                .zip(self.inner.shape().iter())
36                .map(|(&i, n)| i as f64 / (n - 1) as f64)
37                .collect()
38        })
39    }
40
41    fn size_hint(&self) -> (usize, Option<usize>) {
42        self.inner.size_hint()
43    }
44}
45
46impl<'a> ExactSizeIterator for FrequenciesIter<'a> {}
47
48impl<'a> FusedIterator for FrequenciesIter<'a> {}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn test_iter_frequencies_2d() {
56        let spectrum = Spectrum::from_zeros([2, 3]);
57        let mut iter = spectrum.iter_frequencies();
58
59        assert_eq!(iter.len(), 6);
60
61        assert_eq!(iter.next(), Some(vec![0., 0.]));
62        assert_eq!(iter.next(), Some(vec![0., 0.5]));
63        assert_eq!(iter.next(), Some(vec![0., 1.]));
64
65        assert_eq!(iter.len(), 3);
66
67        assert_eq!(iter.next(), Some(vec![1., 0.]));
68        assert_eq!(iter.next(), Some(vec![1., 0.5]));
69        assert_eq!(iter.next(), Some(vec![1., 1.]));
70
71        assert_eq!(iter.len(), 0);
72        assert!(iter.next().is_none());
73    }
74}