From 20b7f57539909c6041894b7d401bbb29c90bec13 Mon Sep 17 00:00:00 2001 From: Milo Mirate Date: Sun, 10 Jan 2021 09:08:41 -0500 Subject: [PATCH 1/6] Add Itertools.counts_by --- src/lib.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 0c6af37e4..7e3402a6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3048,6 +3048,36 @@ pub trait Itertools : Iterator { self.for_each(|item| *counts.entry(item).or_default() += 1); counts } + + /// Collect the items in this iterator and return a `HashMap` which + /// contains each item that appears in the iterator and the number + /// of times it appears, + /// determining identity using a keying function. + /// + /// # Examples + /// ``` + /// # use itertools::Itertools; + /// # use std::collections::HashMap; + /// let counts: HashMap = vec![ + /// (1, "foo"), (1, "bar"), (1, "baz"), + /// (3, "spam"), (3, "eggs"), (5, "foo") + /// ].into_iter().counts_by(|(fst,snd)| fst); + /// assert_eq!(counts[&1], 3); + /// assert_eq!(counts[&3], 2); + /// assert_eq!(counts[&5], 1); + /// assert_eq!(counts.get(&0), None); + /// ``` + #[cfg(feature = "use_std")] + fn counts_by(self, mut f: F) -> HashMap + where + Self: Sized, + K: Eq + Hash, + F: FnMut(Self::Item) -> K, + { + let mut counts = HashMap::new(); + self.for_each(|item| *counts.entry(f(item)).or_default() += 1); + counts + } } impl Itertools for T where T: Iterator { } From 7cf4af605a14ab25deed24c42fa232803f95d5e9 Mon Sep 17 00:00:00 2001 From: Milo Mirate Date: Sun, 10 Jan 2021 14:42:57 -0500 Subject: [PATCH 2/6] Improve brevity+elegance at the cost of greater reliance on compiler optimizations. --- src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7e3402a6d..d1f5daeca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3074,9 +3074,7 @@ pub trait Itertools : Iterator { K: Eq + Hash, F: FnMut(Self::Item) -> K, { - let mut counts = HashMap::new(); - self.for_each(|item| *counts.entry(f(item)).or_default() += 1); - counts + self.map(f).counts() } } From 8d313d54a366f60919061f4d908b5eedf9c6f123 Mon Sep 17 00:00:00 2001 From: Milo Mirate Date: Tue, 12 Jan 2021 07:55:53 -0500 Subject: [PATCH 3/6] Update src/lib.rs --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index d1f5daeca..3dd39ee53 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3068,7 +3068,7 @@ pub trait Itertools : Iterator { /// assert_eq!(counts.get(&0), None); /// ``` #[cfg(feature = "use_std")] - fn counts_by(self, mut f: F) -> HashMap + fn counts_by(self, f: F) -> HashMap where Self: Sized, K: Eq + Hash, From eb165f415aa1e3cfd156fddab748d1b733291ff7 Mon Sep 17 00:00:00 2001 From: Milo Mirate Date: Wed, 13 Jan 2021 21:04:46 -0500 Subject: [PATCH 4/6] Update src/lib.rs Co-authored-by: Jack Wrenn --- src/lib.rs | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3dd39ee53..b9cc0dbd4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3054,18 +3054,31 @@ pub trait Itertools : Iterator { /// of times it appears, /// determining identity using a keying function. /// - /// # Examples /// ``` - /// # use itertools::Itertools; - /// # use std::collections::HashMap; - /// let counts: HashMap = vec![ - /// (1, "foo"), (1, "bar"), (1, "baz"), - /// (3, "spam"), (3, "eggs"), (5, "foo") - /// ].into_iter().counts_by(|(fst,snd)| fst); - /// assert_eq!(counts[&1], 3); - /// assert_eq!(counts[&3], 2); - /// assert_eq!(counts[&5], 1); - /// assert_eq!(counts.get(&0), None); + /// struct Character { + /// first_name: &'static str, + /// last_name: &'static str, + /// } + /// + /// let characters = + /// vec![ + /// Character { first_name: "Amy", last_name: "Pond" }, + /// Character { first_name: "Amy", last_name: "Wong" }, + /// Character { first_name: "Amy", last_name: "Santiago" }, + /// Character { first_name: "James", last_name: "Bond" }, + /// Character { first_name: "James", last_name: "Sullivan" }, + /// Character { first_name: "James", last_name: "Norington" }, + /// Character { first_name: "James", last_name: "Kirk" }, + /// ]; + /// + /// let first_name_frequency = + /// characters + /// .into_iter() + /// .counts_by(|c| c.first_name); + /// + /// assert_eq!(first_name_frequency["Amy"], 3); + /// assert_eq!(first_name_frequency["James"], 4); + /// assert_eq!(first_name_frequency.contains_key("Asha"), false); /// ``` #[cfg(feature = "use_std")] fn counts_by(self, f: F) -> HashMap From 738cfd5e0fd23b5548092d1efd0470eac1af9147 Mon Sep 17 00:00:00 2001 From: Milo Mirate Date: Wed, 13 Jan 2021 21:10:05 -0500 Subject: [PATCH 5/6] Update src/lib.rs --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index b9cc0dbd4..92495881e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3055,6 +3055,7 @@ pub trait Itertools : Iterator { /// determining identity using a keying function. /// /// ``` + # use itertools::Itertools; /// struct Character { /// first_name: &'static str, /// last_name: &'static str, From e0960958c722768a9a4d81a0ea3ed5ba47a40554 Mon Sep 17 00:00:00 2001 From: Milo Mirate Date: Wed, 13 Jan 2021 21:11:42 -0500 Subject: [PATCH 6/6] Update lib.rs --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 92495881e..c5a6151ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3055,7 +3055,7 @@ pub trait Itertools : Iterator { /// determining identity using a keying function. /// /// ``` - # use itertools::Itertools; + /// # use itertools::Itertools; /// struct Character { /// first_name: &'static str, /// last_name: &'static str,