Scala
Median
Implementation
Programming
Algorithms

scala median implementation

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

The median is the middle value of a sorted dataset, and it is often more informative than the average when outliers would distort the result. Implementing it in Scala is not difficult, but a solid solution should handle empty input, odd and even lengths, and numeric conversion cleanly. The simplest correct version sorts the sequence and then reads the middle element or middle pair.

That approach is not the most asymptotically optimal for huge datasets, but it is usually the right tradeoff for clarity unless profiling proves otherwise. In everyday Scala code, a small, explicit implementation is better than a clever one that nobody wants to debug later.

A Simple Median Function for Seq[Double]

The most direct implementation accepts Seq[Double], sorts it, and returns an Option[Double] so empty input is handled explicitly.

scala
1object MedianExample {
2  def median(values: Seq[Double]): Option[Double] = {
3    val sorted = values.sorted
4    val n = sorted.length
5
6    if (n == 0) {
7      None
8    } else if (n % 2 == 1) {
9      Some(sorted(n / 2))
10    } else {
11      val upper = sorted(n / 2)
12      val lower = sorted(n / 2 - 1)
13      Some((lower + upper) / 2.0)
14    }
15  }
16
17  def main(args: Array[String]): Unit = {
18    println(median(Seq(9.0, 1.0, 4.0)))
19    println(median(Seq(9.0, 1.0, 4.0, 7.0)))
20    println(median(Seq.empty[Double]))
21  }
22}

This version is easy to read and correct for both odd and even lengths. Returning None for empty input avoids inventing a fake median value.

Make the Function Generic With Numeric

If you want to accept Int, Long, or other numeric types, Scala's Numeric type class helps. You still need to decide what type to return, and Double is often the most practical common result.

scala
1object GenericMedian {
2  def median[T](values: Seq[T])(implicit num: Numeric[T]): Option[Double] = {
3    import num._
4
5    val sorted = values.sorted(Ordering.by(num.toDouble))
6    val n = sorted.length
7
8    if (n == 0) {
9      None
10    } else if (n % 2 == 1) {
11      Some(num.toDouble(sorted(n / 2)))
12    } else {
13      val lower = num.toDouble(sorted(n / 2 - 1))
14      val upper = num.toDouble(sorted(n / 2))
15      Some((lower + upper) / 2.0)
16    }
17  }
18}

This keeps the call site flexible:

scala
println(GenericMedian.median(Seq(1, 3, 9, 10)))
println(GenericMedian.median(Seq(2L, 5L, 8L)))

The tradeoff is that numeric conversion becomes part of the design. If exact rational arithmetic matters, Double may not be the right return type.

Why Sorting Is Usually Fine

The sort-based solution runs in O(n log n) time. A theoretical O(n) median algorithm exists using selection techniques, but it is more complex and rarely necessary for ordinary business code.

In practice, the sort-based version wins because it is:

  • short
  • easy to test
  • easy to explain in code review
  • reliable for moderate input sizes

If the input is huge and median calculation is a proven bottleneck, then it is time to evaluate a selection algorithm or streaming approach. Until then, clarity is the better engineering choice.

Handle Edge Cases Deliberately

A few details deserve explicit decisions.

First, empty input should not silently return 0.0. That hides bugs. Option[Double] forces the caller to acknowledge the empty case.

Second, even-length sequences require averaging the two middle elements. If the input is integer-based, converting to Double avoids accidental integer division.

Third, if the data contains NaN, sorting and comparison behavior may become surprising. For statistical workloads, clean the input before calculating the median.

A Small Test Example

Median code is compact, so a few focused tests go a long way.

scala
assert(MedianExample.median(Seq(1.0, 3.0, 2.0)).contains(2.0))
assert(MedianExample.median(Seq(1.0, 2.0, 3.0, 4.0)).contains(2.5))
assert(MedianExample.median(Seq.empty[Double]).isEmpty)

These three cases cover the core branches: odd length, even length, and empty input.

Common Pitfalls

The most common mistake is forgetting to sort before choosing the middle element. Median is defined on ordered data.

Another issue is returning integer division for even-length integer sequences. The midpoint between 2 and 3 should be 2.5, not 2.

A third problem is ignoring the empty-input case and letting the code throw an index error deep inside the implementation.

Summary

  • The simplest correct Scala median implementation sorts the sequence and inspects the middle element or pair.
  • 'Option[Double] is a clean way to represent the absence of a median for empty input.'
  • 'Numeric lets you generalize the function beyond Double inputs.'
  • The sort-based approach is O(n log n) and usually the right clarity-performance tradeoff.
  • Test odd, even, and empty cases explicitly.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.