filter, filterNot, and partition
Split and select elements using predicate-based functions.
filter, filterNot, and partition is a free Kotlin Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Selection Operations
filter keeps elements matching a predicate. filterNot keeps those that do NOT match. partition splits the collection into two lists at once.
Basic filter
filter { ... } returns a new list containing only elements where the predicate is true.
fun main() {
val nums = listOf(1, 2, 3, 4, 5, 6)
val evens = nums.filter { it % 2 == 0 }
println(evens) // [2, 4, 6]
}filterNot
filterNot { ... } is the inverse: keep elements where the predicate is false. Same result as inverting the predicate, but clearer intent.
fun main() {
val nums = listOf(1, 2, 3, 4, 5, 6)
val odds = nums.filterNot { it % 2 == 0 }
println(odds) // [1, 3, 5]
}partition
partition returns a Pair: matching elements first, non-matching second. Avoids two passes over the data.
fun main() {
val nums = listOf(1, 2, 3, 4, 5, 6)
val (evens, odds) = nums.partition { it % 2 == 0 }
println("evens=$evens odds=$odds")
}partition with Data Class
Split a list of records into two groups in one pass.
data class User(val name: String, val active: Boolean)
fun main() {
val users = listOf(User("Ada", true), User("Ben", false), User("Cal", true))
val (active, inactive) = users.partition { it.active }
println("active=${active.map { it.name }}")
println("inactive=${inactive.map { it.name }}")
}filterIndexed
Predicate receives both index and value — useful when position matters.
fun main() {
val nums = listOf(10, 20, 30, 40, 50)
val every2nd = nums.filterIndexed { i, _ -> i % 2 == 0 }
println(every2nd) // [10, 30, 50]
}filterIsInstance
Keep only elements of a specific type — smart-casts inside.
fun main() {
val mixed: List<Any> = listOf(1, "hello", 2.0, "world", 3)
val onlyStrings = mixed.filterIsInstance<String>()
println(onlyStrings) // [hello, world]
}filterNotNull
Strip null entries from a list of nullables — returns a list of non-null elements.
fun main() {
val mixed: List<String?> = listOf("a", null, "b", null, "c")
val nonNull = mixed.filterNotNull()
println(nonNull) // [a, b, c]
}Chaining filter and map
Combine filter and map for selection-plus-transformation pipelines.
data class Product(val name: String, val price: Double, val inStock: Boolean)
fun main() {
val products = listOf(
Product("Pen", 1.0, true),
Product("Book", 12.0, false),
Product("Lamp", 25.0, true)
)
val availableNames = products.filter { it.inStock }.map { it.name }
println(availableNames) // [Pen, Lamp]
}Negating with filterNot for Clarity
Sometimes filterNot { it.isActive } reads better than filter { !it.isActive }.
data class Task(val title: String, val done: Boolean)
fun main() {
val tasks = listOf(Task("Email", true), Task("Lunch", false), Task("Code", true))
val pending = tasks.filterNot { it.done }
println(pending) // [Task(title=Lunch, done=false)]
}partition Returns Lists
The Pair from partition contains two regular Lists — destructure them or access via .first / .second.
fun main() {
val nums = (1..10).toList()
val result = nums.partition { it > 5 }
println("above 5: ${result.first}")
println("below 6: ${result.second}")
}partition vs Two filter Calls
If you need both subsets, partition is faster — one pass instead of two.
fun main() {
val nums = (1..10).toList()
// Two passes:
val a = nums.filter { it > 5 }
val b = nums.filter { it <= 5 }
// One pass:
val (c, d) = nums.partition { it > 5 }
println("$a $b")
println("$c $d")
}Quick Check
Which function returns BOTH the matching and non-matching elements in a single pass?
Recap
filter selects matches; filterNot selects non-matches; partition returns both groups in one pass. Use filterIsInstance to keep elements of a type and filterNotNull to drop nulls. Chain with map for selection-plus-transformation.
Frequently asked questions
Is the “filter, filterNot, and partition” lesson free?
Yes — the full text of “filter, filterNot, and partition” is free to read here on the web, and the Kotlin Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Kotlin Academy course, upgrade to CoddyKit PRO.
What will I learn in “filter, filterNot, and partition”?
Split and select elements using predicate-based functions. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Kotlin Academy?
No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “filter, filterNot, and partition” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Kotlin Academy lesson?
Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.