Scala Map Filter Reduce

Map, filter, and reduce are the three fundamental operations in functional programming. Together they replace most loops and cover the vast majority of data-processing patterns. Mastering these three gives you the tools to transform, select, and aggregate any collection in Scala.

map — Transform Every Element

map applies a function to every element and returns a new collection of the same size with transformed values. The original collection is never modified.


Input:  [1, 2, 3, 4, 5]
           ↓  ↓  ↓  ↓  ↓   apply f(x) = x * x
Output: [1, 4, 9,16,25]
val numbers = List(1, 2, 3, 4, 5)

val squares   = numbers.map(n => n * n)         // List(1, 4, 9, 16, 25)
val asStrings = numbers.map(n => s"Item $n")    // List(Item 1, Item 2, ...)
val doubled   = numbers.map(_ * 2)              // List(2, 4, 6, 8, 10)

case class Product(name: String, price: Double)
val products = List(Product("A", 100.0), Product("B", 200.0), Product("C", 300.0))

val withTax = products.map(p => p.copy(price = p.price * 1.18))
withTax.foreach(p => println(f"${p.name}: ₹${p.price}%.2f"))
// A: ₹118.00
// B: ₹236.00
// C: ₹354.00

filter — Keep Matching Elements

filter tests each element against a predicate (a Boolean function) and keeps only those that return true. The output collection is smaller or equal in size.


Input:  [1, 2, 3, 4, 5, 6, 7, 8]
        keep if even?
Output: [2, 4, 6, 8]
val nums = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

val evens       = nums.filter(_ % 2 == 0)        // List(2,4,6,8,10)
val bigOnes     = nums.filter(_ > 6)             // List(7,8,9,10)
val notTwos     = nums.filterNot(_ == 2)         // all except 2
val inRange     = nums.filter(n => n >= 4 && n <= 7)  // List(4,5,6,7)

val words = List("scala", "java", "python", "ruby", "kotlin")
val longWords = words.filter(_.length > 4)
println(longWords)   // List(scala, python, kotlin)

reduce — Combine All Elements

reduce collapses a collection into a single value by repeatedly applying a combining function. It does not take an initial value — it uses the first element as the starting point.


Input: [1, 2, 3, 4, 5]
       fold: (acc, x) => acc + x
Step 1: acc = 1
Step 2: acc = 1 + 2 = 3
Step 3: acc = 3 + 3 = 6
Step 4: acc = 6 + 4 = 10
Step 5: acc = 10 + 5 = 15
Output: 15
val nums = List(1, 2, 3, 4, 5)

val sum     = nums.reduce(_ + _)      // 15
val product = nums.reduce(_ * _)      // 120
val maxVal  = nums.reduce(_ max _)    // 5
val minVal  = nums.reduce(_ min _)    // 1

val words = List("Scala", "is", "powerful")
val sentence = words.reduce(_ + " " + _)  // "Scala is powerful"

foldLeft — reduce with Initial Value

foldLeft is like reduce but takes a starting accumulator value. This makes it safe for empty collections and allows the result type to differ from the element type:

val nums = List(1, 2, 3, 4, 5)

// foldLeft(initial)(combiner)
nums.foldLeft(0)(_ + _)     // 15   (sum)
nums.foldLeft(1)(_ * _)     // 120  (product)
nums.foldLeft(100)(_ + _)   // 115  (100 + sum)

// Result type differs from element type
val wordLengths = List("hello", "world", "scala")
val totalChars = wordLengths.foldLeft(0)((acc, w) => acc + w.length)
println(totalChars)   // 15

Combining All Three

case class Order(product: String, qty: Int, price: Double, category: String)

val orders = List(
  Order("Laptop",     1, 75000.0, "Electronics"),
  Order("Pen",      100,    15.0, "Stationery"),
  Order("Phone",      2, 35000.0, "Electronics"),
  Order("Notebook",  50,    80.0, "Stationery"),
  Order("Headphone",  3,  3000.0, "Electronics")
)

val electronicRevenue =
  orders
    .filter(_.category == "Electronics")          // keep electronics
    .map(o => o.qty * o.price)                    // compute revenue per order
    .reduce(_ + _)                                // total

println(f"Electronics Revenue: ₹$electronicRevenue%,.0f")
// Electronics Revenue: ₹2,29,000

orders
  │
  ▼ filter(Electronics)
  [Laptop, Phone, Headphone]
  │
  ▼ map(qty * price)
  [75000, 70000, 9000]
  │
  ▼ reduce(_ + _)
  154000   ← wait, Laptop=75000, Phone=35000*2=70000, Headphone=3000*3=9000 = 154000

flatMap — Map then Flatten

val sentences = List("hello world", "scala is fun", "map filter reduce")
val allWords  = sentences.flatMap(_.split(" "))
println(allWords)
// List(hello, world, scala, is, fun, map, filter, reduce)

// Equivalent to:
sentences.map(_.split(" ").toList).flatten

collect — Partial Function as map + filter

val mixed: List[Any] = List(1, "two", 3, "four", 5, "six")

val onlyInts = mixed.collect { case n: Int => n * 10 }
println(onlyInts)   // List(10, 30, 50)

Real-World Pipeline

case class Employee(name: String, dept: String, salary: Double, active: Boolean)

val employees = List(
  Employee("Aarav",  "Engineering", 85000.0, true),
  Employee("Diya",   "HR",          55000.0, true),
  Employee("Rohan",  "Engineering", 92000.0, false),
  Employee("Priya",  "Engineering", 78000.0, true),
  Employee("Kiran",  "HR",          62000.0, true)
)

val avgEngSalary =
  employees
    .filter(e => e.dept == "Engineering" && e.active)
    .map(_.salary)
    .reduce(_ + _) / employees.count(e => e.dept == "Engineering" && e.active)

println(f"Avg active Engineering salary: ₹$avgEngSalary%,.0f")
// Avg active Engineering salary: ₹81,500

val deptTotals =
  employees
    .filter(_.active)
    .groupBy(_.dept)
    .map { (dept, emps) => dept -> emps.map(_.salary).sum }

deptTotals.toList.sortBy(_._1).foreach { (dept, total) =>
  println(f"$dept: ₹$total%,.0f")
}
// Engineering: ₹163,000
// HR: ₹117,000

Leave a Comment

Your email address will not be published. Required fields are marked *