1. Overview

In this tutorial, we’ll see how we can find the element with maximum value in a Scala Map.

2. Find the Element With Max Value in a Map in Scala

Given a Map with a number of elements, we may want to extract the element with the max value according to some metric/function.

Let’s start by considering a Map[String, Int]:

scala> val m = Map("a" -> 1, "b" -> 2, "c" -> 3)
val m: Map[String, Int] = Map(a -> 1, b -> 2, c -> 3)

And now we can use a few different standard methods from the Map class:

scala> m.max
val res0: (String, Int) = (c,3)

scala> m.maxBy(_._2)
val res1: (String, Int) = (c,3)

scala> m.maxBy((k,v) => -v)
val res2: (String, Int) = (a,1)

In the first example, we use Map.max() which assumes an implicit ordering of the map’s values. Since we’re using integers, it’s capable of finding the max element.

In the second example, we make use of Map.maxBy(), which receives a function to extract the value of the element before computing the max. In this example, we don’t provide any meaningful function. But in the third example, we pass a function that assigns the negative value for each element. In this latter case, the originally smaller value is not the biggest. Hence we return the (“a”, 1) tuple as the biggest according to the passed function.

We should note that according to the function documentation, if multiple elements return the same computed value, then the first one found is the one returned.

2.1. Maps With More Complex Elements

In the previous examples, we were using a very simple Map where the values were integers. Let’s see how we could work this out if we had a more complex value, like a case class:

scala> case class SomeData(i: Int, d: Double, s: String)
// defined case class SomeData

scala> val m = Map("a" -> SomeData(0, 0.0, "aaa"), "b" -> SomeData(1, 1.0, "bbb"), "c" -> SomeData(2, 2.0, "ccc"))
val m: Map[String, SomeData] = Map(a -> SomeData(0,0.0,aaa), b -> SomeData(1,1.0,bbb), c -> SomeData(2,2.0,ccc))

Let’s start by trying to use the Map.max() method once again:

scala> m.max
1 |m.max
  |     ^
  |No implicit Ordering defined for B
  |
  |where:    B is a type variable with constraint >: (String, SomeData)
  |..
  |I found:
  |
  |    scala.math.Ordering.Tuple2[T1, T2](scala.math.Ordering.String,
  |      scala.math.Ordering.comparatorToOrdering[A](
  |        /* missing */summon[java.util.Comparator[T2]]
  |      )
  |    )
  |
  |But no implicit values were found that match type java.util.Comparator[T2].

It failed because the compiler doesn’t know how to compare our newly created case class.

We can use the Map.maxBy() method to compute the value of each element to be used in the comparison:

scala> m.maxBy((k,v) => v.i)
val res3: (String, SomeData) = (c,SomeData(2,2.0,ccc))

This allows us to get the element with the max value from a Map, whatever the element class or structure is, as long as we pass a function that’s able to compute the corresponding value.

2.2. Maps With Multiple Max Values

Let’s consider the following Map:

scala> val m = Map("a" -> 1, "b" -> 2, "c" -> 3, "d"->3)
val m: Map[String, Int] = Map(a -> 1, b -> 2, c -> 3, d -> 3)

scala> m.max
val res0: (String, Int) = (d,3)

Here, we can see that there are multiple elements that have the same maximum value in the Map. Scala returns one of the elements, but the element returned may be different based on the Scala version. We may need to add additional logic to handle scenarios like this. This could be to ensure there are no repeated values in the map in the first place, or to use a more complex maxBy() function to handle duplicates, etc.

3. Conclusion

In this article, we saw how to find the element with maximum value in a Scala Map.