Scala
Iterable
Top Elements
Programming
Coding Tutorial

Simplest way to get the top n elements of a Scala Iterable

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Getting the top n elements from a Scala Iterable is easy if you are clear about what "top" means. In most cases it means the largest values according to the default ordering, but in real code you often need custom ordering, stable handling of ties, and an approach that matches the size of your data.

The Straightforward Approach

If the collection is small or readability matters more than micro-optimization, sort it and take the last n items. That is the simplest code and is often good enough.

scala
1object TopNBasic extends App {
2  val numbers = List(4, 10, 2, 8, 7, 1)
3  val n = 3
4
5  val topN = numbers.sorted.takeRight(n).reverse
6  println(topN) // List(10, 8, 7)
7}

There are two details worth noting:

  • 'sorted returns ascending order by default.'
  • 'takeRight(n) gives the largest n elements, and reverse makes the result descending.'

This works for any collection whose element type has an implicit Ordering.

Using sortBy for Case Classes

Real applications often work with objects, not raw numbers. In that case, choose the ranking field explicitly with sortBy.

scala
1case class Player(name: String, score: Int)
2
3object TopNPlayers extends App {
4  val players = List(
5    Player("Ava", 18),
6    Player("Ben", 25),
7    Player("Chen", 21),
8    Player("Dia", 25)
9  )
10
11  val topTwo = players.sortBy(_.score).takeRight(2).reverse
12  println(topTwo) // List(Player(Ben,25), Player(Dia,25))
13}

This is still easy to read and makes the ranking rule obvious. For application code, that explicitness is valuable.

A Better Option When n Is Small

Sorting the whole collection costs more than necessary when you only need a few top elements from a very large input. In that case, a priority queue is more efficient because it avoids fully ordering every item.

scala
1import scala.collection.mutable
2
3object TopNWithHeap extends App {
4  val numbers = List(4, 10, 2, 8, 7, 1, 9, 11, 3)
5  val n = 3
6
7  val minHeap = mutable.PriorityQueue.empty[Int](Ordering.Int.reverse)
8
9  numbers.foreach { value =>
10    minHeap.enqueue(value)
11    if (minHeap.size > n) {
12      minHeap.dequeue()
13    }
14  }
15
16  val topN = minHeap.dequeueAll.reverse
17  println(topN.toList) // List(11, 10, 9)
18}

This keeps only the best n values seen so far. For large streams or big collections, that can be much cheaper than sorting everything.

Choosing the Right Collection Method

There is no single best method for every situation:

  • use sorted.takeRight(n).reverse for clarity
  • use sortBy when ranking by a property
  • use a priority queue when performance matters and n is small relative to the collection size

Another option is maxBy or max, but those return only one value. If you need several top elements, they are not the right tool unless you build extra logic around them.

If you want the result in ascending order among the winners, skip the final reverse step. The result shape depends on how the next part of your code consumes it.

Handling Custom Ordering

Sometimes "top" does not mean numerically largest. You may want highest score, shortest duration, or most recent timestamp. Scala's Ordering.by makes that explicit.

scala
1case class Job(name: String, priority: Int, durationMinutes: Int)
2
3object TopNJobs extends App {
4  val jobs = List(
5    Job("import", 2, 15),
6    Job("backup", 5, 120),
7    Job("email", 3, 5)
8  )
9
10  implicit val jobOrdering: Ordering[Job] =
11    Ordering.by((job: Job) => job.priority)
12
13  val topJobs = jobs.sorted.takeRight(2).reverse
14  println(topJobs)
15}

This is useful when you want sorted to work directly on your own type.

Common Pitfalls

The most common mistake is forgetting that sorted is ascending. Developers often write numbers.sorted.take(3) and accidentally get the three smallest elements instead of the three largest.

Another issue is assuming Iterable preserves order. Some implementations, such as Set, do not provide a stable insertion order. If tie behavior matters, convert to a sequence and define the ordering explicitly.

Be careful with large datasets. Full sorting is simple, but it does unnecessary work when you only need a tiny top slice. If performance becomes important, switch to a heap-based approach instead of repeatedly re-sorting.

Finally, think about duplicates. If you need the top n distinct values, add .distinct before sorting or use logic that enforces uniqueness. Otherwise, repeated values are preserved, which may or may not match the requirement.

Summary

  • The simplest Scala solution is sorted.takeRight(n).reverse.
  • Use sortBy when selecting top elements by a field on an object.
  • Use a priority queue for large inputs when n is small.
  • Remember that sorted is ascending by default.
  • Decide early whether duplicates, ordering stability, and tie behavior matter for your use case.

Course illustration
Course illustration

All Rights Reserved.