Como contar instâncias de valores em um mapa

Este é um caso de uso bastante comum com o qual frequentemente me deparo, especialmente como perguntas de novatos no scala.

É por isso que quero compartilhar esta dica realmente básica.

Suponha que temos um Mapde Int -> Intvalores, gerados aleatoriamente

val intMap = (for (id <- 1 to 100) yield (id, Random.nextInt(10))).toMap

> intMap: scala.collection.immutable.Map[Int,Int] = Map(69 -> 2, 88 -> 8, 5 -> 3, 10 -> 9, ... )

As coleções Scala permitem agrupar as entradas que especificam os critérios de agrupamento com uma expressão lambda.

Portanto, podemos agrupar nosso mapa por valores distintos e, em seguida, contar as instâncias de cada valor mapeando nos submapas resultantes obtendo seu tamanho.

No código, isso significa

val occurrences = intMap groupBy {case (id, value) => value} mapValues (_.size)

> occurrences: scala.collection.immutable.Map[Int,Int] = Map(0 -> 10, 5 -> 8, 1 -> 11, 6 -> 10, 9 -> 9, 2 -> 13, 7 -> 9, 3 -> 10, 8 -> 14, 4 -> 6)

Ou usando uma sintaxe mais curta

val occurrences = intMap groupBy (_._2) mapValues (_.size)

Vamos explorar isso passo a passo

  1. quando nós groupBy( docs ), obtemos outro mapa cujas chaves são os valores encontrados em intMap, e cujos valores são um “submapa” de intMap, que contém apenas as entradas relevantes

  2. agora só precisamos transformar cada submapa com mapValues( docs ), obtendo seu tamanho correspondente, para saber quantas ocorrências havia para cada valor no originalintMap


Digamos que você queira saber quantos 5s havia no mapa

val howmanyfives = occurrences(5)

> howmanyfives: Int = 8

Ou, melhor ainda, de uma forma segura

val howmanypossiblyfive = occurrences get 5
> howmanypossiblyfive: Option[Int] = Some(8)

Aproveite o seu histagrama.