Question
I am confused about the difference between fold() and reduce() in Kotlin. Can someone provide a clear example that shows how they differ and when each one should be used?
Short Answer
By the end of this page, you will understand what fold() and reduce() do in Kotlin, how they differ, and when to choose one over the other. You will also see practical examples, common mistakes, and a small mini-project to help you apply the idea.
Concept
fold() and reduce() are Kotlin collection functions used to combine many values into one final result.
For example, you might want to:
- add all numbers in a list
- build a sentence from words
- count values
- transform a list into a map or string
Both functions process items one by one and keep an accumulator value as they go.
The key difference
reduce()
reduce() uses the first element of the collection as the starting accumulator.
That means:
- it only works safely when the collection is not empty
- the accumulator type is usually the same as the element type
fold()
fold() lets you provide your own initial value.
That means:
- it works on empty collections too
- the accumulator can be a different type from the elements
Why this matters
In real programs, collections are often dynamic. Sometimes they are empty. Sometimes the result type is not the same as the item type.
Examples:
- summing prices into a
Double - building a formatted
String - collecting values into a
Map - counting items into an
Int
In these cases, fold() is often more flexible.
Mental rule
- Use
reduce()when the first item can logically act as the starting result. - Use
fold()when you need a custom starting value or need to handle empty collections safely.
Mental Model
Think of both functions like filling out a running total on paper.
- With
reduce(), you start by writing down the first number in the list. - With
fold(), you start by writing down whatever initial value you choose.
Imagine a list:
listOf(2, 3, 4)
Using reduce() is like saying:
- start with
2 - combine with
3 - combine with
4
Using fold(10) is like saying:
- start with
10 - combine with
2 - combine with
3 - combine with
4
So reduce() starts from the collection, while fold() starts from you.
Syntax and Examples
Basic syntax
reduce()
val result = list.reduce { acc, item ->
acc + item
}
accis the current accumulated valueitemis the current element from the list- the first element becomes the initial
acc
fold()
val result = list.fold(initialValue) { acc, item ->
acc + item
}
initialValueis provided by youaccstarts as that initial value
Example 1: Sum numbers
val numbers = listOf(1, 2, 3, 4)
val sumWithReduce = numbers.reduce { acc, n -> acc + n }
val sumWithFold = numbers.fold(0) { acc, n -> acc + n }
println(sumWithReduce) // 10
println(sumWithFold) // 10
Step by Step Execution
Consider this code:
val numbers = listOf(5, 10, 15)
val result = numbers.fold(0) { acc, n -> acc + n }
println(result)
Step by step
Step 1: Create the list
val numbers = listOf(5, 10, 15)
The list contains three integers.
Step 2: Start fold() with initial value 0
numbers.fold(0)
So before processing any elements:
acc = 0
Step 3: Process first element 5
acc + n = 0 + 5 = 5
Now:
acc = 5
Real World Use Cases
Where reduce() is useful
reduce() is useful when:
- the collection is known to be non-empty
- the result type should be the same as the element type
- the first element is a natural starting point
Examples:
- finding the total sum of a non-empty list of numbers
- finding the maximum value in a non-empty list
- combining objects of the same type
val numbers = listOf(3, 7, 2, 9)
val max = numbers.reduce { acc, n -> if (acc > n) acc else n }
println(max) // 9
Where fold() is useful
fold() is useful when:
- the collection might be empty
- you need a custom initial value
- the result type differs from the element type
Examples:
- summing cart prices starting from
0.0 - building a CSV string
- counting matching records
- grouping data into a map
words = listOf(, , )
sentence = words.fold() { acc, word ->
(acc.isEmpty()) word
}
println(sentence)
Real Codebase Usage
In real Kotlin projects, developers often choose fold() because it is safer and more flexible.
Common patterns
Guarding against empty collections
If a list can be empty, fold() avoids runtime errors.
val total = prices.fold(0.0) { acc, price -> acc + price }
Transforming while combining
You may want to turn a list into another structure.
val wordLengths = listOf("cat", "house", "sun")
.fold(mutableMapOf<String, Int>()) { acc, word ->
acc[word] = word.length
acc
}
Building configuration or summary objects
data class Stats(val count: Int, val total: Int)
val stats = listOf(2, 4, 6).fold(Stats(0, 0)) { acc, n ->
Stats(acc.count + 1, acc.total + n)
}
Using when non-empty is guaranteed
Common Mistakes
1. Using reduce() on an empty list
This is the most common problem.
val numbers = emptyList<Int>()
val total = numbers.reduce { acc, n -> acc + n } // error at runtime
How to avoid it
Use fold() if the list may be empty.
val total = numbers.fold(0) { acc, n -> acc + n }
2. Expecting reduce() to accept a custom start value
Broken idea:
// reduce() does not take an initial value like this
val total = listOf(1, 2, 3).reduce(10) { acc, n -> acc + n }
Fix
Use fold().
val total = listOf(1, 2, 3).fold(10) { acc, n -> acc + n }
Comparisons
| Feature | reduce() | fold() |
|---|---|---|
| Initial value | Uses first collection element | Provided by you |
| Works on empty collections | No | Yes |
| Result type can differ from item type | Usually no | Yes |
| Best for | Non-empty collections with same-type result | Flexible accumulation and safe defaults |
| Risk | Throws on empty list | Safer for unknown input |
Quick comparison example
val numbers = listOf(1, 2, 3)
val a = numbers.reduce { acc, n -> acc + n } // 6
val b = numbers.fold() { acc, n -> acc + n }
c = numbers.fold() { acc, n -> acc + n }
Cheat Sheet
Quick rules
reduce()starts with the first elementfold()starts with your initial valuereduce()fails on an empty collectionfold()works on an empty collection- use
fold()when result type differs from element type
Syntax
list.reduce { acc, item ->
// return new accumulator
}
list.fold(initialValue) { acc, item ->
// return new accumulator
}
Examples
val sum1 = listOf(1, 2, 3).reduce { acc, n -> acc + n }
val sum2 = listOf(1, 2, 3).fold(0) { acc, n -> acc + n }
val text = listOf(1, 2, 3).fold("Numbers:") { acc, n -> "$acc $n" }
FAQ
What is the main difference between fold() and reduce() in Kotlin?
reduce() uses the first element as the initial accumulator, while fold() takes an explicit initial value that you provide.
When should I use fold() instead of reduce()?
Use fold() when the collection may be empty, when you need a custom starting value, or when the result type is different from the element type.
Does reduce() work on an empty list in Kotlin?
No. reduce() throws an exception on an empty collection because it has no first element to start with.
Can fold() and reduce() return the same result?
Yes. If you use fold() with an initial value that matches the natural starting value, both can produce the same final result.
Is fold() slower than reduce()?
In normal application code, the difference is usually not important. Choose based on correctness and readability first.
Mini Project
Description
Create a small Kotlin program that processes a list of order amounts. This project demonstrates when fold() is more useful than reduce() by calculating totals safely and building a text summary from the same data.
Goal
Build a Kotlin script that sums order amounts and creates a readable summary string using fold().
Requirements
- Create a list of integer order amounts
- Use
fold()to calculate the total amount starting from0 - Use
fold()again to build a comma-separated summary string - Print both the total and the summary
- Make sure the code still works even if the order list is empty
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.
Android AlarmManager Example: Scheduling Tasks with AlarmManager
Learn how to use Android AlarmManager to schedule tasks, set alarms, and handle broadcasts with a simple beginner example.