easier 0.3.0

making rust easier
Documentation
use super::super::orderedmap::*;

pub trait GroupByExtension: IntoIterator {
    /// Groups by a key and returns an iterator of the key and the values grouped by the key
    /// Order of groups is guaranteed to be in the order they appear
    /// ```rust
    /// use easier::prelude::*;
    /// let vec = ["1", "1", "22", "333", "333", "1"];
    /// let mut map = vec.group_by(|a| a.len());
    /// assert_eq!(map.count(), 3);
    /// ```

    fn group_by<K>(self, f: impl Fn(&Self::Item) -> K) -> IntoIter<K, Self::Item>
    where
        K: Eq + std::hash::Hash + Clone,
        Self: Sized,
    {
        let mut map = OrderedVecMap::new();
        for item in self {
            let key = f(&item);
            map.insert_push(key, item);
        }
        map.into_iter()
    }

    /// Groups by a key and returns an iterator of the key and a user defined value
    /// Order of groups is guaranteed to be in the order they appear
    /// ```rust
    /// use easier::prelude::*;
    /// let vec = ["1", "1", "22", "333", "333", "1"];
    /// let map = vec.group_by_with(|a| a.len(),|v| format!("Val:{}", v)).to_hashmap();
    /// assert_eq!(map.len(), 3);
    /// assert_eq!(map.get(&1).unwrap(), &["Val:1", "Val:1", "Val:1"]);
    /// ```

    fn group_by_with<K, V>(
        self,
        f: impl Fn(&Self::Item) -> K,
        vf: impl Fn(&Self::Item) -> V,
    ) -> IntoIter<K, V>
    where
        K: Eq + std::hash::Hash + Clone,
        Self: Sized,
    {
        let mut map = OrderedVecMap::new();
        for item in self {
            let key = f(&item);
            map.insert_push(key, vf(&item));
        }
        map.into_iter()
    }
}

impl<I> GroupByExtension for I where I: IntoIterator {}

#[cfg(test)]
mod tests {

    use crate::prelude::ToCollectionIteratorExtension;

    use super::*;

    #[test]
    fn can_groupby_array() {
        let vec = [1, 1, 2, 3, 3, 1];
        let map = vec.group_by(|a| *a).to_hashmap();
        assert_eq!(map.len(), 3);
        assert_eq!(map.get(&1).unwrap(), &vec![1, 1, 1]);
        assert_eq!(map.get(&2).unwrap(), &vec![2]);
        assert_eq!(map.get(&3).unwrap(), &vec![3, 3]);
    }

    #[test]
    fn group_by_iter() {
        let vec = [1, 1, 2, 3, 3, 1];
        let map = vec.group_by(|a| *a);
        assert_eq!(map.count(), 3);
        let mut map = vec.group_by(|a| *a);
        //order is not guaranteed
        //assert_eq!(map.next(), Some((1, vec![1, 1, 1])));
        //assert_eq!(map.next(), Some((2, vec![2])));
        //assert_eq!(map.next(), Some((3, vec![3, 3])));
        assert!(map.next().is_some());
        assert!(map.next().is_some());
        assert!(map.next().is_some());
        assert!(map.next().is_none());
    }

    #[test]
    fn can_group_by_vec_strings() {
        //Strings
        let vec = ["1", "1", "22", "333", "333", "1"];
        let map = vec.group_by(|a| a.len()).to_hashmap();

        assert_eq!(map.len(), 3);
        assert_eq!(map.get(&1).unwrap(), &["1", "1", "1"]);
        assert_eq!(map.get(&2).unwrap(), &["22"]);
        assert_eq!(map.get(&3).unwrap(), &["333", "333"]);
    }

    #[test]
    fn group_by_struct() {
        struct Person {
            name: String,
            age: u8,
        }
        let persons = vec![
            Person {
                name: "Alice".to_string(),
                age: 20,
            },
            Person {
                name: "Bob".to_string(),
                age: 20,
            },
            Person {
                name: "Charlie".to_string(),
                age: 30,
            },
            Person {
                name: "Danny".to_string(),
                age: 20,
            },
        ];

        //Strings

        let map = persons.iter().group_by(|a| a.age).to_hashmap();

        assert_eq!(map.len(), 2);
        assert_eq!(map.get(&20).unwrap().len(), 3);
        assert_eq!(map.get(&30).unwrap().len(), 1);
        assert_eq!(map.get(&30).unwrap().first().unwrap().name, "Charlie");

        let map = persons.group_by(|a| a.name.len());
        assert_eq!(map.count(), 3);
    }
    #[test]
    fn group_by_with() {
        struct Person {
            name: String,
            age: u8,
        }
        let persons = vec![
            Person {
                name: "Alice".to_string(),
                age: 20,
            },
            Person {
                name: "Bob".to_string(),
                age: 20,
            },
            Person {
                name: "Charlie".to_string(),
                age: 30,
            },
        ];

        let map = persons
            .iter()
            .group_by_with(|a| a.age, |a| a.name.clone())
            .to_hashmap();

        assert_eq!(map.len(), 2);
        assert_eq!(map.get(&20).unwrap().len(), 2);
        assert_eq!(map.get(&30).unwrap().len(), 1);
        assert_eq!(map.get(&30).unwrap().first().unwrap(), &"Charlie");

        let mut map = persons.group_by_with(|a| a.age, |a| a.name.len());

        assert!(map.next().is_some());
        assert!(map.next().is_some());
        assert!(map.next().is_none());
    }

    #[test]
    fn ordering() {
        let vec = [2, 1, 1, 3, 3, 1];
        let mut map = vec.group_by(|a| *a);
        assert_eq!(map.next(), Some((2, vec![2])));
        assert_eq!(map.next(), Some((1, vec![1, 1, 1])));
        assert_eq!(map.next(), Some((3, vec![3, 3])));
    }
}