lowdash 0.5.3

A Lodash inspired utility library to manipulate array and object for Rust
Documentation
/// Find all unique elements in a collection based on a key generated by the iteratee function.
/// Returns elements whose generated keys appear exactly once.
///
/// # Arguments
/// * `collection` - A slice of items.
/// * `iteratee` - A function that takes an item and returns a key used for uniqueness comparison.
///
/// # Returns
/// * `Vec<T>` - A vector containing only the elements whose generated keys appear exactly once.
///
/// # Examples
/// ```rust
/// use lowdash::find_uniques_by;
/// let numbers = vec![1, 2, 3, 4];
/// let result = find_uniques_by(&numbers, |x| x % 2);  // Group by even/odd
/// assert_eq!(result, vec![]);  // No unique remainders
/// ```
///
/// ```rust
/// use lowdash::find_uniques_by;
///
/// #[derive(Debug, Clone, PartialEq)]
/// struct Person {
///     name: String,
///     age: u32,
/// }
///
/// let people = vec![
///     Person { name: "Alice".to_string(), age: 25 },
///     Person { name: "Bob".to_string(), age: 30 },
///     Person { name: "Carol".to_string(), age: 25 },
/// ];
///
/// let result = find_uniques_by(&people, |p| p.age);
/// assert_eq!(result, vec![Person { name: "Bob".to_string(), age: 30 }]);
/// ```
pub fn find_uniques_by<T, U, F>(collection: &[T], iteratee: F) -> Vec<T>
where
    T: Clone,
    U: Eq + std::hash::Hash,
    F: Fn(&T) -> U,
{
    use std::collections::HashMap;

    let mut key_counts = HashMap::new();

    // Count occurrences of each key
    for item in collection {
        let key = iteratee(item);
        *key_counts.entry(key).or_insert(0) += 1;
    }

    // Collect items whose keys appear exactly once
    collection
        .iter()
        .filter(|item| key_counts.get(&iteratee(item)) == Some(&1))
        .cloned()
        .collect()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_find_uniques_by_remainder() {
        let numbers = vec![1, 2, 3, 4];
        let result = find_uniques_by(&numbers, |x| x % 2);
        assert_eq!(result, vec![]); // No unique remainders
    }

    #[test]
    fn test_find_uniques_by_length() {
        let words = vec!["a", "ab", "abc", "ab", "abcd"];
        let result = find_uniques_by(&words, |s| s.len());
        assert_eq!(result, vec!["a", "abc", "abcd"]);
    }

    #[test]
    fn test_find_uniques_by_empty() {
        let collection: Vec<i32> = vec![];
        let result = find_uniques_by(&collection, |x| x % 2);
        assert_eq!(result, Vec::<i32>::new());
    }

    #[test]
    fn test_find_uniques_by_with_struct() {
        #[derive(Debug, Clone, PartialEq)]
        struct Person {
            name: String,
            age: u32,
        }

        let people = vec![
            Person {
                name: "Alice".to_string(),
                age: 25,
            },
            Person {
                name: "Bob".to_string(),
                age: 30,
            },
            Person {
                name: "Carol".to_string(),
                age: 25,
            },
        ];

        // Test uniqueness by age
        let result = find_uniques_by(&people, |p| p.age);
        assert_eq!(
            result,
            vec![Person {
                name: "Bob".to_string(),
                age: 30,
            }]
        );

        // Test uniqueness by name first letter
        let name_result = find_uniques_by(&people, |p| p.name.chars().next().unwrap());
        assert_eq!(
            name_result,
            vec![
                Person {
                    name: "Alice".to_string(),
                    age: 25,
                },
                Person {
                    name: "Bob".to_string(),
                    age: 30,
                },
                Person {
                    name: "Carol".to_string(),
                    age: 25,
                }
            ]
        );
    }

    #[test]
    fn test_find_uniques_by_all_unique() {
        let numbers = vec![1, 2, 3];
        let result = find_uniques_by(&numbers, |x| x * 2);
        assert_eq!(result, vec![1, 2, 3]);
    }

    #[test]
    fn test_find_uniques_by_all_same() {
        let numbers = vec![1, 2, 3, 4];
        let result = find_uniques_by(&numbers, |_| 1);
        assert_eq!(result, Vec::<i32>::new());
    }
}