use crate::Count;
use std::collections::btree_map::{self, BTreeMap};
use std::iter::FromIterator;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MultiSet<E: Ord, C: Count> {
occurrences: BTreeMap<E, C>,
}
impl<E: Ord, C: Count> MultiSet<E, C> {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
MultiSet {
occurrences: BTreeMap::new(),
}
}
pub fn from<I: IntoIterator<Item = (E, C)>>(iter: I) -> Self {
MultiSet {
occurrences: BTreeMap::from_iter(iter),
}
}
pub fn add<I: IntoIterator<Item = (E, C)>>(&mut self, iter: I) {
for (elem, by) in iter {
self.add_elem(elem, by);
}
}
pub fn add_elem(&mut self, elem: E, by: C) {
let count = self.occurrences.entry(elem).or_insert_with(Count::zero);
count.add(by);
}
pub fn count(&self, elem: &E) -> C {
self.occurrences
.get(elem)
.map_or(Count::zero(), |&count| count)
}
pub fn iter(&self) -> impl DoubleEndedIterator<Item = (&E, &C)> {
self.occurrences.iter()
}
}
impl<E: Ord> MultiSet<E, u64> {
pub fn threshold(&self, threshold: u64) -> Vec<&E> {
self.threshold_iter(threshold).collect()
}
pub fn threshold_iter(&self, threshold: u64) -> impl Iterator<Item = &E> {
self.occurrences
.iter()
.filter(move |(_, &count)| count >= threshold)
.map(|(elem, _)| elem)
}
pub fn elem_count(&self) -> usize {
self.occurrences.len()
}
}
pub struct IntoIter<E: Ord, C: Count>(btree_map::IntoIter<E, C>);
impl<E: Ord, C: Count> Iterator for IntoIter<E, C> {
type Item = (E, C);
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl<E: Ord, C: Count> IntoIterator for MultiSet<E, C> {
type Item = (E, C);
type IntoIter = IntoIter<E, C>;
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.occurrences.into_iter())
}
}