Today I had a use case, where I needed to check if all elements in an iterator are the same.
I looked at the standard library and itertools
but did not find anything that resembles my use case.
Here's the extension trait that solves my issue:
use std::collections::HashSet;
use std::hash::Hash;
/// An iterator extension that checks if all elements are the same.
///
/// # Examples
/// ```
/// use all_the_same::AllTheSame;
///
/// let v = vec![1, 1, 1, 1];
/// assert_eq!(v.into_iter().all_the_same(), Ok(1));
///
/// let v = vec![1, 2, 1, 1];
/// assert_eq!(v.into_iter().all_the_same(), Err([1, 2].iter().cloned().collect()));
pub trait AllTheSame: Iterator {
/// Returns the first element if all elements are the same.
///
/// # Errors
/// Returns a set of all different elements if they are not the same.
/// Returns an empty set if the iterator is empty.
fn all_the_same(self) -> Result<Self::Item, HashSet<Self::Item>>;
}
impl<T> AllTheSame for T
where
T: Iterator,
<T as Iterator>::Item: Eq + Hash,
{
fn all_the_same(mut self) -> Result<Self::Item, HashSet<Self::Item>> {
let mut seen = HashSet::new();
if let Some(first) = self.next() {
for other in self {
if other != first {
seen.insert(other);
}
}
if seen.is_empty() {
Ok(first)
} else {
seen.insert(first);
Err(seen)
}
} else {
Err(seen)
}
}
}
Did I reinvent the wheel? Can I improve the code?