0

I modified code found on the internet to create a function that obtains the statistical mode of any Hashable type that implements Eq, but I do not understand some of the syntax. Here is the function:

use std::hash::Hash;
use std::collections::HashMap;

pub fn mode<'a, I, T>(items: I) -> &'a T 
where I: IntoIterator<Item = &'a T>, 
      T: Hash + Clone + Eq, {
  let mut occurrences: HashMap<&T, usize> = HashMap::new();

  for value in items.into_iter() {
      *occurrences.entry(value).or_insert(0) += 1;
  }

  occurrences
      .into_iter()
      .max_by_key(|&(_, count)| count)
      .map(|(val, _)| val)
      .expect("Cannot compute the mode of zero items")
}

(I think requiring Clone may be overkill.)

The syntax I do not understand is in the closure passed to map_by_key:

|&(_, count)| count

What is the &(_, count) doing? I gather the underscore means I can ignore that parameter. Is this some sort of destructuring of a tuple in a parameter list? Does this make count take the reference of the tuple's second item?

Paul Chernoch
  • 5,275
  • 3
  • 52
  • 73
  • 1
    It's pattern matching used for destructuring, yes. When your type is `&(_, count)`, `.max_by_key(|&(_, count)| count)` is equivalent to `.max_by_key(|v| v.1)`. It lets you have a cleaner name inside the closure rather than using the `.1` access. – Denys Séguret Apr 14 '21 at 15:00
  • 1
    Related: https://stackoverflow.com/questions/19066402/meaning-of-variable-in-arguments-patterns – E_net4 Apr 14 '21 at 15:10
  • Yes, that related question is helpful, especially about the restriction to Copyable types of & destructuring. – Paul Chernoch Apr 14 '21 at 15:32
  • may_by_key is a function that accepts a closure with one parameter which is a reference to a tuple with two elements. The closure does nothing but returns back only the second element from the tuple. – Sankar Boro Apr 14 '21 at 16:01

1 Answers1

0

.max_by_key(|&(_, count)| count) is equivalent to .max_by_key(f) where f is this:

fn f<T>(t: &(T, usize)) -> usize {
    (*t).1
}

f() could also be written using pattern matching, like this:

fn f2<T>(&(_, count): &(T, usize)) -> usize {
    count
}

And f2() is much closer to the first closure you're asking about.

The second closure is essentially the same, except there is no reference slightly complicating matters.

NovaDenizen
  • 5,089
  • 14
  • 28