Skip to content

Commit 89f3a0d

Browse files
Merge #468
468: Create counts method and tests for it r=jswrenn a=JarredAllen Creates the function described in #467 (I went with the name `counts`). It currently uses `for_each` and makes a `HashMap` manually because the PR for the `into_grouping_map` function is still being worked on, but this function could easily be changed to call it once that PR is merged, if desired. Co-authored-by: JarredAllen <[email protected]>
2 parents 3a28cb6 + 1d05c2b commit 89f3a0d

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

src/lib.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2807,6 +2807,30 @@ pub trait Itertools : Iterator {
28072807
{
28082808
multipeek_impl::multipeek(self)
28092809
}
2810+
2811+
/// Collect the items in this iterator and return a `HashMap` which
2812+
/// contains each item that appears in the iterator and the number
2813+
/// of times it appears.
2814+
///
2815+
/// # Examples
2816+
/// ```
2817+
/// # use itertools::Itertools;
2818+
/// let counts = [1, 1, 1, 3, 3, 5].into_iter().counts();
2819+
/// assert_eq!(counts[&1], 3);
2820+
/// assert_eq!(counts[&3], 2);
2821+
/// assert_eq!(counts[&5], 1);
2822+
/// assert_eq!(counts.get(&0), None);
2823+
/// ```
2824+
#[cfg(feature = "use_std")]
2825+
fn counts(self) -> HashMap<Self::Item, usize>
2826+
where
2827+
Self: Sized,
2828+
Self::Item: Eq + Hash,
2829+
{
2830+
let mut counts = HashMap::new();
2831+
self.for_each(|item| *counts.entry(item).or_default() += 1);
2832+
counts
2833+
}
28102834
}
28112835

28122836
impl<T: ?Sized> Itertools for T where T: Iterator { }

tests/quick.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,3 +1188,24 @@ quickcheck! {
11881188
}
11891189
}
11901190
}
1191+
1192+
quickcheck! {
1193+
#[test]
1194+
fn counts(nums: Vec<isize>) -> TestResult {
1195+
let counts = nums.iter().counts();
1196+
for (&item, &count) in counts.iter() {
1197+
if count <= 0 {
1198+
return TestResult::failed();
1199+
}
1200+
if count != nums.iter().filter(|&x| x == item).count() {
1201+
return TestResult::failed();
1202+
}
1203+
}
1204+
for item in nums.iter() {
1205+
if !counts.contains_key(item) {
1206+
return TestResult::failed();
1207+
}
1208+
}
1209+
TestResult::passed()
1210+
}
1211+
}

0 commit comments

Comments
 (0)