DEV Community

Nikita Zonov
Nikita Zonov

Posted on

Count the number of identical objects in List[_]

Let's assume we have a list of objects


case class Cake(id: Int, name: String, expired: Long)

val l = List(Cake(1,"keks"), Cake(1,"keks"), Cake(1,"keks"), Cake(4,"pie"))
Enter fullscreen mode Exit fullscreen mode

start to count

l.groupBy(_.id).map(pair => (pair._1, pair._2.length))

// res0: scala.collection.immutable.Map[Int,Int] = Map(4 -> 1, 1 -> 3)
Enter fullscreen mode Exit fullscreen mode

good, but what if we wanna get all object as a key

l.groupBy(_.id)
  .map({
    case (_, items) => items.head -> items.length
  })

// res1: scala.collection.immutable.Map[Cake,Int] = Map(Cake(4,pie) -> 1, Cake(1,keks) -> 3)
Enter fullscreen mode Exit fullscreen mode

Match better. When pull request with this code come to review I get comment from my colleague

head is not safety so it's bad

So, we need to change it

l.groupBy(_.id)
  .map({
    case (_, items) => items.headOption.map(_ -> items.length)
  })
// res2: scala.collection.immutable.Iterable[Option[(Cake, Int)]] = List(Some((Cake(4,pie),1)), Some((Cake(1,keks),3)))
Enter fullscreen mode Exit fullscreen mode

And then beautiful trick with List[Option[_]]

l.groupBy(_.id)
  .map({
    case (_, items) => items.headOption.map(_ -> items.length)
  }).flatten

//res3: scala.collection.immutable.Iterable[(Cake, Int)] = List((Cake(4,pie),1), (Cake(1,keks),3))
Enter fullscreen mode Exit fullscreen mode

finishing touch

l.groupBy(_.id)
  .flatMap({
    case (_, items) => items.headOption.map(_ -> items.length)
  })

//res4: scala.collection.immutable.Iterable[(Cake, Int)] = List((Cake(4,pie),1), (Cake(1,keks),3))
Enter fullscreen mode Exit fullscreen mode

Question: Do you agree with my colleague opinion?

Top comments (1)

Collapse
 
jakebman profile image
jakebman

I disagree. In this context, head is guaranteed to exist, as there would not be a pair generated from groupby that is (somekey, EmptyList), as somekey had to come from at least one item.