counter/lib.rs
1//! Counter counts recurrent elements of iterables. It is based on [the Python
2//! implementation](https://docs.python.org/3/library/collections.html#collections.Counter).
3//!
4//! The struct [`Counter`](struct.Counter.html) is the entry-point type for this module.
5//!
6//! # Math Underpinnings
7//!
8//! Mathematically, a `Counter` implements a hash-based version of a [multiset],
9//! or bag. This is simply an extension of the notion of a set to the idea that
10//! we care not only about whether an entity exists within the set, but the number
11//! of occurrences within the set. Normal set operations such as intersection,
12//! union, etc. are of course still supported.
13//!
14//! [multiset]: https://en.wikipedia.org/wiki/Set_(abstract_data_type)#Multiset
15//!
16//! # Examples
17//!
18//! ## Just count an iterable
19//!
20//! ```rust
21//! use counter::Counter;
22//! let char_counts = "barefoot".chars().collect::<Counter<_>>();
23//! let counts_counts = char_counts.values().collect::<Counter<_>>();
24//! ```
25//!
26//! ## Update a count
27//!
28//! ```rust
29//! # use counter::Counter;
30//! let mut counts = "aaa".chars().collect::<Counter<_>>();
31//! counts[&'a'] += 1;
32//! counts[&'b'] += 1;
33//! ```
34//!
35//! ```rust
36//! # use counter::Counter;
37//! let mut counts = "able babble table babble rabble table able fable scrabble"
38//! .split_whitespace().collect::<Counter<_>>();
39//! // add or subtract an iterable of the same type
40//! counts += "cain and abel fable table cable".split_whitespace();
41//! // or add or subtract from another Counter of the same type
42//! let other_counts = "scrabble cabbie fable babble"
43//! .split_whitespace().collect::<Counter<_>>();
44//! let difference = counts - other_counts;
45//! ```
46//!
47//! ## Extend a `Counter` with another `Counter`:
48//! ```rust
49//! # use counter::Counter;
50//! # use std::collections::HashMap;
51//! let mut counter = "abbccc".chars().collect::<Counter<_>>();
52//! let another = "bccddd".chars().collect::<Counter<_>>();
53//! counter.extend(&another);
54//! let expect = [('a', 1), ('b', 3), ('c', 5), ('d', 3)].iter()
55//! .cloned().collect::<HashMap<_, _>>();
56//! assert_eq!(counter.into_map(), expect);
57//! ```
58//! ## Get items with keys
59//!
60//! ```rust
61//! # use counter::Counter;
62//! let counts = "aaa".chars().collect::<Counter<_>>();
63//! assert_eq!(counts[&'a'], 3);
64//! assert_eq!(counts[&'b'], 0);
65//! ```
66//!
67//! ## Get the most common items
68//!
69//! [`most_common_ordered()`] uses the natural ordering of keys which are [`Ord`].
70//!
71//! [`most_common_ordered()`]: Counter::most_common_ordered
72//! [`Ord`]: https://doc.rust-lang.org/stable/std/cmp/trait.Ord.html
73//!
74//! ```rust
75//! # use counter::Counter;
76//! let by_common = "eaddbbccc".chars().collect::<Counter<_>>().most_common_ordered();
77//! let expected = vec![('c', 3), ('b', 2), ('d', 2), ('a', 1), ('e', 1)];
78//! assert!(by_common == expected);
79//! ```
80//!
81//! [`k_most_common_ordered()`] takes an argument `k` of type `usize` and returns the top `k` most
82//! common items. This is functionally equivalent to calling `most_common_ordered()` and then
83//! truncating the result to length `k`. However, if `k` is smaller than the length of the counter
84//! then `k_most_common_ordered()` can be more efficient, often much more so.
85//!
86//! ```rust
87//! # use counter::Counter;
88//! let by_common = "eaddbbccc".chars().collect::<Counter<_>>().k_most_common_ordered(2);
89//! let expected = vec![('c', 3), ('b', 2)];
90//! assert!(by_common == expected);
91//! ```
92//!
93//! [`k_most_common_ordered()`]: Counter::k_most_common_ordered
94//! [`most_common_ordered()`]: Counter::most_common_ordered
95//!
96//! ## Get the most common items using your own ordering
97//!
98//! For example, here we break ties reverse alphabetically.
99//!
100//! ```rust
101//! # use counter::Counter;
102//! let counter = "eaddbbccc".chars().collect::<Counter<_>>();
103//! let by_common = counter.most_common_tiebreaker(|&a, &b| b.cmp(&a));
104//! let expected = vec![('c', 3), ('d', 2), ('b', 2), ('e', 1), ('a', 1)];
105//! assert!(by_common == expected);
106//! ```
107//!
108//! ## Test counters against another
109//!
110//! Counters are multi-sets and so can be sub- or supersets of each other.
111//!
112//! A counter is a _subset_ of another if for all its elements, the other
113//! counter has an equal or higher count. Test for this with [`is_subset()`]:
114//!
115//! ```rust
116//! # use counter::Counter;
117//! let counter = "aaabb".chars().collect::<Counter<_>>();
118//! let superset = "aaabbbc".chars().collect::<Counter<_>>();
119//! let not_a_superset = "aaae".chars().collect::<Counter<_>>();
120//! assert!(counter.is_subset(&superset));
121//! assert!(!counter.is_subset(¬_a_superset));
122//! ```
123//!
124//! Testing for a _superset_ is the inverse, [`is_superset()`] is true if the counter can contain another counter in its entirety:
125//!
126//! ```rust
127//! # use counter::Counter;
128//! let counter = "aaabbbc".chars().collect::<Counter<_>>();
129//! let subset = "aabbb".chars().collect::<Counter<_>>();
130//! let not_a_subset = "aaae".chars().collect::<Counter<_>>();
131//! assert!(counter.is_superset(&subset));
132//! assert!(!counter.is_superset(¬_a_subset));
133//! ```
134//!
135//! These relationships continue to work when [using a _signed_ integer type for the counter][signed]: all values in the subset must be equal or lower to the values in the superset. Negative
136//! values are interpreted as 'missing' those values, and the subset would need to miss those
137//! same elements, or be short more, to still be a subset:
138//!
139//! ```rust
140//! # use counter::Counter;
141//! let mut subset = "aaabb".chars().collect::<Counter<_, i8>>();
142//! subset.insert('e', -2); // short 2 'e's
143//! subset.insert('f', -1); // and 1 'f'
144//! let mut superset = "aaaabbb".chars().collect::<Counter<_, i8>>();
145//! superset.insert('e', -1); // short 1 'e'
146//! assert!(subset.is_subset(&superset));
147//! assert!(superset.is_superset(&subset));
148//! ```
149//!
150//! [`is_subset()`]: Counter::is_subset
151//! [`is_superset()`]: Counter::is_superset
152//! [signed]: #use-your-own-type-for-the-count
153//!
154//! ## Counter intersection and union
155//!
156//! You can intersect two counters, giving you the minimal counts of their
157//! combined elements using the [`&` bitwise and operator][BitAnd], and produce
158//! their union with the maximum counts using [`|` bitwise or][BitOr]:
159//!
160//! ```rust
161//! # use counter::Counter;
162//! let a = "aaabb".chars().collect::<Counter<_>>();
163//! let b = "aabbbbe".chars().collect::<Counter<_>>();
164//!
165//! let intersection = a & b;
166//! let expected_intersection = "aabb".chars().collect::<Counter<_>>();
167//! assert_eq!(intersection, expected_intersection);
168//!
169//! let c = "aaabb".chars().collect::<Counter<_>>();
170//! let d = "aabbbbe".chars().collect::<Counter<_>>();
171//!
172//! let union = c | d;
173//! let expected_union = "aaabbbbe".chars().collect::<Counter<_>>();
174//! assert_eq!(union, expected_union)
175//! ```
176//!
177//! The in-place [`&=`] and [`|=`] operations are also supported.
178//!
179//! [BitAnd]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
180//! [BitOr]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
181//! [`&=`]: https://doc.rust-lang.org/std/ops/trait.BitAndAssign.html
182//! [`|=`]: https://doc.rust-lang.org/std/ops/trait.BitOrAssign.html
183//!
184//! ## Treat it like a `HashMap`
185//!
186//! `Counter<T, N>` implements [`Deref`]`<Target=HashMap<T, N>>` and
187//! [`DerefMut`]`<Target=HashMap<T, N>>`, which means that you can perform any operations
188//! on it which are valid for a [`HashMap`].
189//!
190//! [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html
191//! [`Deref`]: https://doc.rust-lang.org/stable/std/ops/trait.Deref.html
192//! [`DerefMut`]: https://doc.rust-lang.org/stable/std/ops/trait.DerefMut.html
193//!
194//! ```rust
195//! # use counter::Counter;
196//! let mut counter = "aa-bb-cc".chars().collect::<Counter<_>>();
197//! counter.remove(&'-');
198//! assert!(counter == "aabbcc".chars().collect::<Counter<_>>());
199//! ```
200//!
201//! Note that `Counter<T, N>` itself implements [`Index`]. `Counter::index` returns a reference to
202//! a [`Zero::zero`] value for missing keys.
203//!
204//! [`Index`]: https://doc.rust-lang.org/stable/std/ops/trait.Index.html
205//! [`Zero::zero`]: https://docs.rs/num-traits/latest/num_traits/identities/trait.Zero.html#tymethod.zero
206//!
207//! ```rust
208//! # use counter::Counter;
209//! let counter = "aaa".chars().collect::<Counter<_>>();
210//! assert_eq!(counter[&'b'], 0);
211//! // panics
212//! // assert_eq!((*counter)[&'b'], 0);
213//! ```
214//!
215//! # Advanced Usage
216//!
217//! ## Count any iterable which is `Hash + Eq`
218//!
219//! You can't use the `most_common*` functions unless `T` is also [`Clone`], but simple counting
220//! works fine on a minimal data type.
221//!
222//! [`Clone`]: https://doc.rust-lang.org/stable/std/clone/trait.Clone.html
223//!
224//! ```rust
225//! # use counter::Counter;
226//! #[derive(Debug, Hash, PartialEq, Eq)]
227//! struct Inty {
228//! i: usize,
229//! }
230//!
231//! impl Inty {
232//! pub fn new(i: usize) -> Inty {
233//! Inty { i: i }
234//! }
235//! }
236//!
237//! // <https://en.wikipedia.org/wiki/867-5309/Jenny>
238//! let intys = vec![
239//! Inty::new(8),
240//! Inty::new(0),
241//! Inty::new(0),
242//! Inty::new(8),
243//! Inty::new(6),
244//! Inty::new(7),
245//! Inty::new(5),
246//! Inty::new(3),
247//! Inty::new(0),
248//! Inty::new(9),
249//! ];
250//!
251//! let inty_counts = intys.iter().collect::<Counter<_>>();
252//! println!("{:?}", inty_counts);
253//! // {Inty { i: 8 }: 2, Inty { i: 0 }: 3, Inty { i: 9 }: 1, Inty { i: 3 }: 1,
254//! // Inty { i: 7 }: 1, Inty { i: 6 }: 1, Inty { i: 5 }: 1}
255//! assert!(inty_counts.get(&Inty { i: 8 }) == Some(&2));
256//! assert!(inty_counts.get(&Inty { i: 0 }) == Some(&3));
257//! assert!(inty_counts.get(&Inty { i: 6 }) == Some(&1));
258//! ```
259//!
260//! ## Use your own type for the count
261//!
262//! Sometimes [`usize`] just isn't enough. If you find yourself overflowing your
263//! machine's native size, you can use your own type. Here, we use an [`i8`], but
264//! you can use most numeric types, including bignums, as necessary.
265//!
266//! [`usize`]: https://doc.rust-lang.org/stable/std/primitive.usize.html
267//! [`i8`]: https://doc.rust-lang.org/stable/std/primitive.i8.html
268//!
269//! ```rust
270//! # use counter::Counter;
271//! # use std::collections::HashMap;
272//! let counter: Counter<_, i8> = "abbccc".chars().collect();
273//! let expected: HashMap<char, i8> = [('a', 1), ('b', 2), ('c', 3)].iter().cloned().collect();
274//! assert!(counter.into_map() == expected);
275//! ```
276
277#![allow(clippy::must_use_candidate)]
278mod impls;
279
280use num_traits::{One, Zero};
281
282use std::collections::{BinaryHeap, HashMap};
283use std::hash::{BuildHasher, Hash, RandomState};
284use std::iter;
285use std::ops::{AddAssign, SubAssign};
286#[cfg(test)]
287mod unit_tests;
288
289#[derive(Clone, Debug)]
290pub struct Counter<T, N = usize, S = RandomState> {
291 map: HashMap<T, N, S>,
292 // necessary for `Index::index` since we cannot declare generic `static` variables.
293 zero: N,
294}
295
296impl<T, N, S> PartialEq for Counter<T, N, S>
297where
298 T: Eq + Hash,
299 N: PartialEq,
300 S: BuildHasher,
301{
302 fn eq(&self, other: &Self) -> bool {
303 // ignore the zero
304 self.map == other.map
305 }
306}
307
308impl<T, N, S> Eq for Counter<T, N, S>
309where
310 T: Eq + Hash,
311 N: Eq,
312 S: BuildHasher,
313{
314}
315
316impl<T, N> Counter<T, N> {
317 /// Consumes this counter and returns a [`HashMap`] mapping the items to the counts.
318 ///
319 /// [`HashMap`]: https://doc.rust-lang.org/stable/std/collections/struct.HashMap.html
320 pub fn into_map(self) -> HashMap<T, N> {
321 self.map
322 }
323
324 /// Returns the sum of the counts.
325 ///
326 /// Use [`len`] to get the number of elements in the counter and use `total` to get the sum of
327 /// their counts.
328 ///
329 /// [`len`]: struct.Counter.html#method.len
330 ///
331 /// # Examples
332 ///
333 /// ```
334 /// # use counter::Counter;
335 /// let counter = "abracadabra".chars().collect::<Counter<_>>();
336 /// assert_eq!(counter.total::<usize>(), 11);
337 /// assert_eq!(counter.len(), 5);
338 /// ```
339 pub fn total<'a, S>(&'a self) -> S
340 where
341 S: iter::Sum<&'a N>,
342 {
343 self.map.values().sum()
344 }
345}
346
347impl<T, N, S> Counter<T, N, S>
348where
349 T: Hash + Eq,
350 N: AddAssign + Zero + One,
351 S: BuildHasher,
352{
353 /// Add the counts of the elements from the given iterable to this counter.
354 pub fn update<I>(&mut self, iterable: I)
355 where
356 I: IntoIterator<Item = T>,
357 {
358 for item in iterable {
359 let entry = self.map.entry(item).or_insert_with(N::zero);
360 *entry += N::one();
361 }
362 }
363}
364
365impl<T, N, S> Counter<T, N, S>
366where
367 T: Hash + Eq,
368 N: PartialOrd + SubAssign + Zero + One,
369 S: BuildHasher,
370{
371 /// Remove the counts of the elements from the given iterable to this counter.
372 ///
373 /// Non-positive counts are automatically removed.
374 ///
375 /// ```rust
376 /// # use counter::Counter;
377 /// # use std::collections::HashMap;
378 /// let mut counter = "abbccc".chars().collect::<Counter<_>>();
379 /// counter.subtract("abba".chars());
380 /// let expect = [('c', 3)].iter().cloned().collect::<HashMap<_, _>>();
381 /// assert_eq!(counter.into_map(), expect);
382 /// ```
383 pub fn subtract<I>(&mut self, iterable: I)
384 where
385 I: IntoIterator<Item = T>,
386 {
387 for item in iterable {
388 let mut remove = false;
389 if let Some(entry) = self.map.get_mut(&item) {
390 if *entry > N::zero() {
391 *entry -= N::one();
392 }
393 remove = *entry == N::zero();
394 }
395 if remove {
396 self.map.remove(&item);
397 }
398 }
399 }
400}
401
402impl<T, N, S> Counter<T, N, S>
403where
404 T: Hash + Eq + Clone,
405 N: Clone + Ord,
406{
407 /// Create a vector of `(elem, frequency)` pairs, sorted most to least common.
408 ///
409 /// ```rust
410 /// # use counter::Counter;
411 /// let mc = "pappaopolo".chars().collect::<Counter<_>>().most_common();
412 /// let expected = vec![('p', 4), ('o', 3), ('a', 2), ('l', 1)];
413 /// assert_eq!(mc, expected);
414 /// ```
415 ///
416 /// Note that the ordering of duplicates is unstable.
417 pub fn most_common(&self) -> Vec<(T, N)> {
418 use std::cmp::Ordering;
419 self.most_common_tiebreaker(|_a, _b| Ordering::Equal)
420 }
421
422 /// Create a vector of `(elem, frequency)` pairs, sorted most to least common.
423 ///
424 /// In the event that two keys have an equal frequency, use the supplied ordering function
425 /// to further arrange the results.
426 ///
427 /// For example, we can sort reverse-alphabetically:
428 ///
429 /// ```rust
430 /// # use counter::Counter;
431 /// let counter = "eaddbbccc".chars().collect::<Counter<_>>();
432 /// let by_common = counter.most_common_tiebreaker(|&a, &b| b.cmp(&a));
433 /// let expected = vec![('c', 3), ('d', 2), ('b', 2), ('e', 1), ('a', 1)];
434 /// assert_eq!(by_common, expected);
435 /// ```
436 pub fn most_common_tiebreaker<F>(&self, mut tiebreaker: F) -> Vec<(T, N)>
437 where
438 F: FnMut(&T, &T) -> ::std::cmp::Ordering,
439 {
440 let mut items = self
441 .map
442 .iter()
443 .map(|(key, count)| (key.clone(), count.clone()))
444 .collect::<Vec<_>>();
445 items.sort_unstable_by(|(a_item, a_count), (b_item, b_count)| {
446 b_count
447 .cmp(a_count)
448 .then_with(|| tiebreaker(a_item, b_item))
449 });
450 items
451 }
452}
453
454impl<T, N, S> Counter<T, N, S>
455where
456 T: Hash + Eq + Clone + Ord,
457 N: Clone + Ord,
458{
459 /// Create a vector of `(elem, frequency)` pairs, sorted most to least common.
460 ///
461 /// In the event that two keys have an equal frequency, use the natural ordering of the keys
462 /// to further sort the results.
463 ///
464 /// # Examples
465 ///
466 /// ```rust
467 /// # use counter::Counter;
468 /// let mc = "abracadabra".chars().collect::<Counter<_>>().most_common_ordered();
469 /// let expect = vec![('a', 5), ('b', 2), ('r', 2), ('c', 1), ('d', 1)];
470 /// assert_eq!(mc, expect);
471 /// ```
472 ///
473 /// # Time complexity
474 ///
475 /// *O*(*n* \* log *n*), where *n* is the number of items in the counter. If all you want is
476 /// the top *k* items and *k* < *n* then it can be more efficient to use
477 /// [`k_most_common_ordered`].
478 ///
479 /// [`k_most_common_ordered`]: Counter::k_most_common_ordered
480 pub fn most_common_ordered(&self) -> Vec<(T, N)> {
481 self.most_common_tiebreaker(Ord::cmp)
482 }
483
484 /// Returns the `k` most common items in decreasing order of their counts.
485 ///
486 /// The returned vector is the same as would be obtained by calling `most_common_ordered` and
487 /// then truncating the result to length `k`. In particular, items with the same count are
488 /// sorted in *increasing* order of their keys. Further, if `k` is greater than the length of
489 /// the counter then the returned vector will have length equal to that of the counter, not
490 /// `k`.
491 ///
492 /// # Examples
493 ///
494 /// ```rust
495 /// # use counter::Counter;
496 /// let counter: Counter<_> = "abracadabra".chars().collect();
497 /// let top3 = counter.k_most_common_ordered(3);
498 /// assert_eq!(top3, vec![('a', 5), ('b', 2), ('r', 2)]);
499 /// ```
500 ///
501 /// # Time complexity
502 ///
503 /// This method can be much more efficient than [`most_common_ordered`] when *k* is much
504 /// smaller than the length of the counter *n*. When *k* = 1 the algorithm is equivalent
505 /// to finding the minimum (or maximum) of *n* items, which requires *n* \- 1 comparisons. For
506 /// a fixed value of *k* > 1, the number of comparisons scales with *n* as *n* \+ *O*(log *n*)
507 /// and the number of swaps scales as *O*(log *n*). As *k* approaches *n*, this algorithm
508 /// approaches a heapsort of the *n* items, which has complexity *O*(*n* \* log *n*).
509 ///
510 /// For values of *k* close to *n* the sorting algorithm used by [`most_common_ordered`] will
511 /// generally be faster than the heapsort used by this method by a small constant factor.
512 /// Exactly where the crossover point occurs will depend on several factors. For small *k*
513 /// choose this method. If *k* is a substantial fraction of *n*, it may be that
514 /// [`most_common_ordered`] is faster. If performance matters in your application then it may
515 /// be worth experimenting to see which of the two methods is faster.
516 ///
517 /// [`most_common_ordered`]: Counter::most_common_ordered
518 pub fn k_most_common_ordered(&self, k: usize) -> Vec<(T, N)> {
519 use std::cmp::Reverse;
520
521 if k == 0 {
522 return vec![];
523 }
524
525 // The quicksort implementation used by `most_common_ordered()` is generally faster than
526 // the heapsort used below when sorting the entire counter.
527 if k >= self.map.len() {
528 return self.most_common_ordered();
529 }
530
531 // Clone the counts as we iterate over the map to eliminate an extra indirection when
532 // comparing counts. This will be an improvement in the typical case where `N: Copy`.
533 // Defer cloning the keys until we have selected the top `k` items so that we clone only
534 // `k` keys instead of all of them.
535 let mut items = self.map.iter().map(|(t, n)| (Reverse(n.clone()), t));
536
537 // Step 1. Make a heap out of the first `k` items; this makes O(k) comparisons.
538 let mut heap: BinaryHeap<_> = items.by_ref().take(k).collect();
539
540 // Step 2. Successively compare each of the remaining `n - k` items to the top of the heap,
541 // replacing the root (and subsequently sifting down) whenever the item is less than the
542 // root. This takes at most n - k + k * (1 + log2(k)) * (H(n) - H(k)) comparisons, where
543 // H(i) is the ith [harmonic number](https://en.wikipedia.org/wiki/Harmonic_number). For
544 // fixed `k`, this scales as *n* + *O*(log(*n*)).
545 items.for_each(|item| {
546 // If `items` is nonempty at this point then we know the heap contains `k > 0`
547 // elements.
548 let mut root = heap.peek_mut().expect("the heap is empty");
549 if *root > item {
550 *root = item;
551 }
552 });
553
554 // Step 3. Sort the items in the heap with the second phases of heapsort. The number of
555 // comparisons is 2 * k * log2(k) + O(k).
556 heap.into_sorted_vec()
557 .into_iter()
558 .map(|(Reverse(n), t)| (t.clone(), n))
559 .collect()
560 }
561}
562
563impl<T, N, S> Counter<T, N, S>
564where
565 T: Hash + Eq,
566 N: PartialOrd + Zero,
567 S: BuildHasher,
568{
569 /// Test whether this counter is a superset of another counter.
570 /// This is true if for all elements in this counter and the other,
571 /// the count in this counter is greater than or equal to the count in the other.
572 ///
573 /// `c.is_superset(&d);` -> `c.iter().all(|(x, n)| n >= d[x]) && d.iter().all(|(x, n)| c[x] >= n)`
574 ///
575 /// ```rust
576 /// # use counter::Counter;
577 /// # use std::collections::HashMap;
578 /// let c = "aaabbc".chars().collect::<Counter<_>>();
579 /// let mut d = "abb".chars().collect::<Counter<_>>();
580 ///
581 /// assert!(c.is_superset(&d));
582 /// d[&'e'] = 1;
583 /// assert!(!c.is_superset(&d));
584 /// ```
585 pub fn is_superset(&self, other: &Self) -> bool {
586 // need to test keys from both counters, because if N is signed, counts in `self`
587 // could be < 0 for elements missing in `other`. For the unsigned case, only elements
588 // from `other` would need to be tested.
589 self.keys()
590 .chain(other.keys())
591 .all(|key| self[key] >= other[key])
592 }
593
594 /// Test whether this counter is a subset of another counter.
595 /// This is true if for all elements in this counter and the other,
596 /// the count in this counter is less than or equal to the count in the other.
597 ///
598 /// `c.is_subset(&d);` -> `c.iter().all(|(x, n)| n <= d[x]) && d.iter().all(|(x, n)| c[x] <= n)`
599 ///
600 /// ```rust
601 /// # use counter::Counter;
602 /// # use std::collections::HashMap;
603 /// let mut c = "abb".chars().collect::<Counter<_>>();
604 /// let mut d = "aaabbc".chars().collect::<Counter<_>>();
605 ///
606 /// assert!(c.is_subset(&d));
607 /// c[&'e'] = 1;
608 /// assert!(!c.is_subset(&d));
609 /// ```
610 pub fn is_subset(&self, other: &Self) -> bool {
611 // need to test keys from both counters, because if N is signed, counts in `other`
612 // could be < 0 for elements missing in `self`. For the unsigned case, only elements
613 // from `self` would need to be tested.
614 self.keys()
615 .chain(other.keys())
616 .all(|key| self[key] <= other[key])
617 }
618}