#![doc = include_str!("../README.md")]
use std::collections::{HashMap, hash_map::Entry};
pub struct Uniques<'a, T> {
pub unique_idx: HashMap<&'a T, usize>,
pub first_idx: HashMap<&'a T, usize>,
pub duplicate_idx: HashMap<&'a T, Vec<usize>>,
pub subsequent_idx: HashMap<&'a T, Vec<usize>>,
pub unique: HashMap<usize, &'a T>,
pub first: HashMap<usize, &'a T>,
pub duplicate: HashMap<usize, &'a T>,
pub subsequent: HashMap<usize, &'a T>,
}
impl<'a, T> Uniques<'a, T> {
pub fn new(items: &'a [T]) -> Uniques<'a, T>
where
T: std::hash::Hash + Eq,
{
let mut unique_idx = HashMap::new();
let mut first_idx = HashMap::new();
let mut duplicate_idx = HashMap::new();
let mut subsequent_idx = HashMap::new();
let mut unique = HashMap::new();
let mut first = HashMap::new();
let mut duplicate = HashMap::new();
let mut subsequent = HashMap::new();
for (i, x) in items.iter().enumerate() {
match first_idx.entry(x) {
Entry::Vacant(first_idx_x) => {
first_idx_x.insert(i);
first.insert(i, x);
unique_idx.insert(x, i);
unique.insert(i, x);
}
Entry::Occupied(first_idx_x) => {
let first_i = *first_idx_x.get();
duplicate_idx
.entry(x)
.and_modify(|v: &mut Vec<_>| v.push(i))
.or_insert_with(|| {
duplicate.insert(first_i, first[&first_i]);
vec![first_i, i]
});
duplicate.insert(i, x);
subsequent_idx
.entry(x)
.and_modify(|v: &mut Vec<_>| v.push(i))
.or_insert_with(|| vec![i]);
subsequent.insert(i, x);
if let Some(j) = unique_idx.remove(x) {
unique.remove(&j);
}
}
}
}
Uniques {
unique_idx,
first_idx,
duplicate_idx,
subsequent_idx,
unique,
first,
duplicate,
subsequent,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn integers_empty() {
let input: &[usize] = &[];
let unique_idx = HashMap::new();
let first_idx = HashMap::new();
let duplicate_idx = HashMap::new();
let subsequent_idx = HashMap::new();
let unique = HashMap::new();
let first = HashMap::new();
let duplicate = HashMap::new();
let subsequent = HashMap::new();
let result = Uniques::new(input);
assert_eq!(result.unique_idx, unique_idx);
assert_eq!(result.first_idx, first_idx);
assert_eq!(result.duplicate_idx, duplicate_idx);
assert_eq!(result.subsequent_idx, subsequent_idx);
assert_eq!(result.unique, unique);
assert_eq!(result.first, first);
assert_eq!(result.duplicate, duplicate);
assert_eq!(result.subsequent, subsequent);
}
#[test]
fn integers_no_duplicates() {
let input = &[0, 1, 2];
let unique_idx = HashMap::from([(&0, 0), (&1, 1), (&2, 2)]);
let first_idx = HashMap::from([(&0, 0), (&1, 1), (&2, 2)]);
let duplicate_idx = HashMap::new();
let subsequent_idx = HashMap::new();
let unique = HashMap::from([(0, &0), (1, &1), (2, &2)]);
let first = HashMap::from([(0, &0), (1, &1), (2, &2)]);
let duplicate = HashMap::new();
let subsequent = HashMap::new();
let result = Uniques::new(input);
assert_eq!(result.unique_idx, unique_idx);
assert_eq!(result.first_idx, first_idx);
assert_eq!(result.duplicate_idx, duplicate_idx);
assert_eq!(result.subsequent_idx, subsequent_idx);
assert_eq!(result.unique, unique);
assert_eq!(result.first, first);
assert_eq!(result.duplicate, duplicate);
assert_eq!(result.subsequent, subsequent);
}
#[test]
fn integers_with_duplicates() {
let input = &[0, 1, 2, 0, 1];
let unique_idx = HashMap::from([(&2, 2)]);
let first_idx = HashMap::from([(&0, 0), (&1, 1), (&2, 2)]);
let duplicate_idx = HashMap::from([(&0, vec![0, 3]), (&1, vec![1, 4])]);
let subsequent_idx = HashMap::from([(&0, vec![3]), (&1, vec![4])]);
let unique = HashMap::from([(2, &2)]);
let first = HashMap::from([(0, &0), (1, &1), (2, &2)]);
let duplicate = HashMap::from([(0, &0), (1, &1), (3, &0), (4, &1)]);
let subsequent = HashMap::from([(3, &0), (4, &1)]);
let result = Uniques::new(input);
assert_eq!(result.unique_idx, unique_idx);
assert_eq!(result.first_idx, first_idx);
assert_eq!(result.duplicate_idx, duplicate_idx);
assert_eq!(result.subsequent_idx, subsequent_idx);
assert_eq!(result.unique, unique);
assert_eq!(result.first, first);
assert_eq!(result.duplicate, duplicate);
assert_eq!(result.subsequent, subsequent);
}
#[test]
fn strs_empty() {
let input: &[&str] = &[];
let unique_idx = HashMap::new();
let first_idx = HashMap::new();
let duplicate_idx = HashMap::new();
let subsequent_idx = HashMap::new();
let unique = HashMap::new();
let first = HashMap::new();
let duplicate = HashMap::new();
let subsequent = HashMap::new();
let result = Uniques::new(input);
assert_eq!(result.unique_idx, unique_idx);
assert_eq!(result.first_idx, first_idx);
assert_eq!(result.duplicate_idx, duplicate_idx);
assert_eq!(result.subsequent_idx, subsequent_idx);
assert_eq!(result.unique, unique);
assert_eq!(result.first, first);
assert_eq!(result.duplicate, duplicate);
assert_eq!(result.subsequent, subsequent);
}
#[test]
fn strs_no_duplicates() {
let input = &["a", "b", "c"];
let unique_idx = HashMap::from([(&"a", 0), (&"b", 1), (&"c", 2)]);
let first_idx = HashMap::from([(&"a", 0), (&"b", 1), (&"c", 2)]);
let duplicate_idx = HashMap::new();
let subsequent_idx = HashMap::new();
let unique = HashMap::from([(0, &"a"), (1, &"b"), (2, &"c")]);
let first = HashMap::from([(0, &"a"), (1, &"b"), (2, &"c")]);
let duplicate = HashMap::new();
let subsequent = HashMap::new();
let result = Uniques::new(input);
assert_eq!(result.unique_idx, unique_idx);
assert_eq!(result.first_idx, first_idx);
assert_eq!(result.duplicate_idx, duplicate_idx);
assert_eq!(result.subsequent_idx, subsequent_idx);
assert_eq!(result.unique, unique);
assert_eq!(result.first, first);
assert_eq!(result.duplicate, duplicate);
assert_eq!(result.subsequent, subsequent);
}
#[test]
fn strs_with_duplicates() {
let input = &["a", "b", "c", "a", "b"];
let unique_idx = HashMap::from([(&"c", 2)]);
let first_idx = HashMap::from([(&"a", 0), (&"b", 1), (&"c", 2)]);
let duplicate_idx = HashMap::from([(&"a", vec![0, 3]), (&"b", vec![1, 4])]);
let subsequent_idx = HashMap::from([(&"a", vec![3]), (&"b", vec![4])]);
let unique = HashMap::from([(2, &"c")]);
let first = HashMap::from([(0, &"a"), (1, &"b"), (2, &"c")]);
let duplicate = HashMap::from([(0, &"a"), (1, &"b"), (3, &"a"), (4, &"b")]);
let subsequent = HashMap::from([(3, &"a"), (4, &"b")]);
let result = Uniques::new(input);
assert_eq!(result.unique_idx, unique_idx);
assert_eq!(result.first_idx, first_idx);
assert_eq!(result.duplicate_idx, duplicate_idx);
assert_eq!(result.subsequent_idx, subsequent_idx);
assert_eq!(result.unique, unique);
assert_eq!(result.first, first);
assert_eq!(result.duplicate, duplicate);
assert_eq!(result.subsequent, subsequent);
}
}