Kotlin Copilot: Divisible by 7
Video: Kotlin Copilot: Divisible by 7 by Taught by Celeste AI - AI Coding Coach
Kotlin: Count Numbers Divisible by 7
numbers.count { it % 7 == 0 }— one line. Thecount(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 % 0throwsArithmeticException. Guard ifdivisorcould be zero. - Negative numbers.
-14 % 7 == 0is 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.