0Pricing
Kotlin Academy · Lesson

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.

All lessons in this course

  1. map and flatMap: Transforming Every Element
  2. filter, filterNot, and partition
  3. fold, reduce, and runningFold
  4. Chaining Pipelines and Avoiding Intermediate Lists with Sequence
← Back to Kotlin Academy