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
