Part of Github Copilot with Kotlin

Kotlin Copilot: Divisible by 7

Sandy LaneSandy Lane

Video: Kotlin Copilot: Divisible by 7 by Taught by Celeste AI - AI Coding Coach

Take the quiz on the full lesson page
Test what you've read · interactive walkthrough

Kotlin: Count Numbers Divisible by 7

numbers.count { it % 7 == 0 } — one line. The count(predicate) extension is the canonical "how many match" idiom.

A small Kotlin idiom: count items in a list that satisfy a predicate. The naive way uses a for-loop with a counter; the idiomatic way is count { ... }.

The Copilot prompt

fun main() {
  val numbers = listOf(14, 21, 33, 42, 55, 63, 70, 81)
  // Count how many numbers are divisible by 7

Copilot generates:

val divisibleBy7Count = numbers.count { it % 7 == 0 }
println("Count of numbers divisible by 7: $divisibleBy7Count")

Output:

Count of numbers divisible by 7: 5

(14, 21, 42, 63, 70 — five numbers.)

Walkthrough

Iterable<T>.count(predicate) walks the iterable, runs the predicate on each element, returns the count of elements where the predicate is true.

The lambda { it % 7 == 0 }: - it is the implicit name for the single parameter (here, an Int). - it % 7 == 0 is a Boolean — true when it divides evenly by 7.

count(predicate) differs from count(): - count() (no args) returns the size — same as .size. - count(p) returns "how many satisfy p."

Related: filter, then count

val divisibles = numbers.filter { it % 7 == 0 }
val count = divisibles.size

Two passes: filter builds an intermediate list, then .size. count(predicate) skips the intermediate list — one pass, no allocation.

For very large lists, count(predicate) is faster.

any, all, none

numbers.any { it % 7 == 0 }    // true if at least one is divisible
numbers.all { it % 7 == 0 }    // true if all are
numbers.none { it % 7 == 0 }   // true if zero are

For "is there at least one match?" use any — short-circuits on first true, faster than count > 0.

For "are all matches?" use all. For "no matches at all?" use none.

With other predicates

numbers.count { it > 50 }              // count > 50
numbers.count { it.toString().length == 2 }  // 2-digit numbers
numbers.count { it % 2 == 0 && it % 3 == 0 } // divisible by 6

Predicates can be any (T) -> Boolean. Multiple conditions joined with && or ||.

On strings, maps, sequences

count(predicate) is on Iterable<T>, String, Sequence<T>, and other collection types:

"Hello, World!".count { it.isUpperCase() }   // 2 (H, W)

val words = mapOf("apple" to 5, "banana" to 6, "cherry" to 6)
words.count { it.value == 6 }   // 2 ("banana", "cherry")

val sequence = (1..1_000_000).asSequence()
sequence.count { it % 7 == 0 }   // 142857 — same idiom, lazy evaluation

Storing the divisibles

If you also want the matching values, not just the count:

val divisibles = numbers.filter { it % 7 == 0 }
val count = divisibles.size
println("Found ${count} divisibles: $divisibles")

filter allocates a new list. For one pass that captures both:

val (divisibles, others) = numbers.partition { it % 7 == 0 }
println("${divisibles.size} divisibles: $divisibles")
println("${others.size} non-divisibles: $others")

partition returns a Pair<List<T>, List<T>> — first part matches, second doesn't. One pass.

Generalizing to "divisible by N"

fun List<Int>.countDivisibleBy(n: Int): Int =
  count { it % n == 0 }

println(numbers.countDivisibleBy(7))   // 5
println(numbers.countDivisibleBy(3))   // 3

Extension function on List<Int>. Reusable.

Edge cases

  • Empty list. Returns 0. No predicate evaluations.
  • Modulo with zero divisor. n % 0 throws ArithmeticException. Guard if divisor could be zero.
  • Negative numbers. -14 % 7 == 0 is true (Kotlin's % matches the sign of the dividend, but for divisibility checks it doesn't matter — both are zero when divisible).
  • Floating point modulo. Double.rem(divisor) works but has precision quirks. For floats, prefer "abs(x % d) < epsilon" if checking near-divisibility.

Common mistakes

Filter-then-size. Works but allocates. Use count(predicate).

count(predicate) confused with count(). Same name, different meaning. count() (no args) is just the size.

Using filter().size > 0 for "any match." Use any { ... } — short-circuits.

Modulo ambiguity. (-7) % 3 differs by language. Kotlin/Java match the dividend's sign: -7 % 3 == -1. For "true mathematical modulo," use Math.floorMod(-7, 3) == 2.

it % 7 == 0 on a Double. Double.rem(7) == 0.0 works but float precision means (0.7 / 0.1).rem(1.0) may not be 0.0. Use integer arithmetic when divisibility matters.

What's next

Episode 15: Jetpack Compose — a button with a callback. The simplest Compose UI: one widget, one click handler.

Recap

numbers.count { it % 7 == 0 } for "how many match." count(predicate) is one pass, no intermediate allocation. any/all/none for "is at least one / are all / are none?" — any short-circuits on first match. partition { ... } if you need both the matches and non-matches in one pass.

Next episode: a button with a callback.

Ready? Take the quiz on the full lesson page →
Test what you've learned. Watch the lesson and try the interactive quiz on the same page.