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(&not_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(&not_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}