use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::hash::Hash;
pub enum Duplicates {
First,
Last,
None,
}
impl Duplicates {
pub fn duplicated<T>(a: &[T], how: Duplicates) -> Vec<bool>
where T: Clone + Hash + Eq
{
match how {
Duplicates::First => Duplicates::duplicated_keepfirst(a),
Duplicates::Last => Duplicates::duplicated_keeplast(a),
Duplicates::None => Duplicates::duplicated_keepnone(a),
}
}
fn duplicated_keepfirst<T>(a: &[T]) -> Vec<bool>
where T: Clone + Hash + Eq
{
let mut res: Vec<bool> = Vec::with_capacity(a.len());
let mut set: HashSet<Cow<T>> = HashSet::with_capacity(a.len());
for v in a.iter().map(|x| Cow::Borrowed(x)) {
if set.contains(&v) {
res.push(true)
} else {
set.insert(v);
res.push(false);
}
}
res
}
fn duplicated_keeplast<T>(a: &[T]) -> Vec<bool>
where T: Clone + Hash + Eq
{
let mut res: Vec<bool> = Vec::with_capacity(a.len());
let mut map: HashMap<Cow<T>, usize> = HashMap::with_capacity(a.len());
for (i, v) in a.iter().enumerate() {
match map.entry(Cow::Borrowed(v)) {
Entry::Occupied(mut e) => {
let idx = e.insert(i);
res[idx] = true;
res.push(false);
}
Entry::Vacant(e) => {
e.insert(i);
res.push(false);
}
}
}
res
}
fn duplicated_keepnone<T>(a: &[T]) -> Vec<bool>
where T: Clone + Hash + Eq
{
let mut res: Vec<bool> = Vec::with_capacity(a.len());
let mut map: HashMap<Cow<T>, usize> = HashMap::with_capacity(a.len());
for (i, v) in a.iter().enumerate() {
match map.entry(Cow::Borrowed(v)) {
Entry::Occupied(e) => {
res[*e.get()] = true;
res.push(true);
}
Entry::Vacant(e) => {
e.insert(i);
res.push(false);
}
}
}
res
}
}
#[cfg(test)]
mod tests {
use super::Duplicates;
#[test]
fn test_vec_duplicates_int() {
let key = vec![1, 1, 2, 3, 1, 2, 1];
let res = Duplicates::duplicated(&key, Duplicates::First);
assert_eq!(res, vec![false, true, false, false, true, true, true]);
let res = Duplicates::duplicated(&key, Duplicates::Last);
assert_eq!(res, vec![true, true, true, false, true, false, false]);
let res = Duplicates::duplicated(&key, Duplicates::None);
assert_eq!(res, vec![true, true, true, false, true, true, true]);
}
#[test]
fn test_vec_duplicates_str() {
let key = vec!["a", "b", "c", "b", "a", "c", "d", "b"];
let res = Duplicates::duplicated(&key, Duplicates::First);
assert_eq!(res,
vec![false, false, false, true, true, true, false, true]);
let res = Duplicates::duplicated(&key, Duplicates::Last);
assert_eq!(res,
vec![true, true, true, true, false, false, false, false]);
let res = Duplicates::duplicated(&key, Duplicates::None);
assert_eq!(res, vec![true, true, true, true, true, true, false, true]);
}
}