skip to content

In Kotlin, how do you check whether a value lies inside a range, and what does the `in` operator do under the hood for a range like `1..10`?

level: juniorimportance: must knowfreq 78%

answer

  1. `a in b` == `b.contains(a)`
  2. `..` ranges are inclusive at BOTH ends
  3. membership is O(1) comparison, not iteration
  4. `!in` negates
  5. great inside `when` branches

basics

~10 s

Use the in keyword: x in 1..10 is true when x is between 1 and 10, both ends included. !in checks the opposite. It calls the range's contains method.

solid answer

~40 s

Write `value in range` to test membership; it returns a `Boolean`. For `1..10` (an `IntRange`, both endpoints inclusive), `x in 1..10` compiles to `(1..10).contains(x)`. The `in` operator is sugar for the `contains` operator function, and `!in` negates it. Because `IntRange` overrides `contains` with a simple `first <= value && value <= last` comparison (no iteration), the check is O(1). You can use `in` in `if`, `while`, and especially `when` branches: `when (x) { in 1..10 -> ... }`. The same syntax works for `CharRange` and `LongRange`. Mixing types matters: `1.5 in 1..10` won't compile because `1..10` is an `IntRange`; you'd use `1.0..10.0` (a `ClosedFloatingPointRange`) instead.

code

kotlin · 9 lines
kotlin
val temp = 23
val comfortable = temp in 18..26      // true, == (18..26).contains(23)
val label = when (temp) {
    in Int.MIN_VALUE..0 -> "freezing"
    in 1..17            -> "cold"
    in 18..26           -> "comfortable"
    else                -> "hot"
}
println(label)                          // comfortable

go deeper

for a junior

Knows x in 1..10, that both ends are inclusive, and that !in negates.

for a middle

Explains in desugars to contains and that numeric membership is an O(1) comparison, not a loop.

for a senior

Connects in to the operator-overloading convention and notes the type-matching rule (Int vs Double ranges).

for a principal

Discusses when in semantics differ across range types and why contains overrides matter for performance and API design.

## What `in` means for ranges A **range** in Kotlin is an object describing a closed interval. `1..10` creates an `IntRange` whose endpoints are **both inclusive** (1 and 10 are members). The `in` operator answers the yes/no question "is this value a member?" and returns a `Boolean`. ## `in` is operator sugar for `contains` Kotlin translates `a in b` into `b.contains(a)` — the receiver is the range on the **right**, the candidate value is on the **left**. `!in` translates to `!b.contains(a)`. This is the **operator-overloading convention**: any type that declares an `operator fun contains(...)` supports `in`. ```kotlin val r = 1..10 println(5 in r) // true -> r.contains(5) println(0 in r) // false println(10 in r) // true (last endpoint is inclusive) println(7 !in r) // false -> !r.contains(7) ``` ## It's a comparison, not a loop For numeric ranges, `contains` does **not** iterate. `IntRange.contains` is essentially `first <= value && value <= last`, so the test is **O(1)** regardless of how big the range is — `1_000_000 in 1..1_000_000_000` is instant. ## Works anywhere a Boolean is expected ```kotlin if (score in 0..100) { /* valid */ } while (i in 1..n) { /* ... */ } val grade = when (score) { in 90..100 -> "A" in 80..89 -> "B" else -> "F" } ``` The `when (subject)` form is a very common place to use `in` because each branch reads as a clean membership test. ## Type must match the range `1..10` is an `IntRange`. Putting a `Double` on the left (`1.5 in 1..10`) fails to compile because there is no `contains(Double)` on `IntRange`. For floating-point intervals use `1.0..10.0`, which is a `ClosedFloatingPointRange<Double>`.

  • What does `x !in 1..10` compile to?
    `!(1..10).contains(x)` — the same `contains` call, negated.
  • Is `10 in 1..10` true or false?
    True. The `..` operator produces a range that is inclusive on both ends, so the last endpoint is a member.

in is like asking a bouncer 'is my number on the guest list between 1 and 10?' — one glance, not reading every name.

saying these in an interview costs you the question

  • Saying `in` iterates the whole range to find the value (it's a comparison for numeric ranges).
  • Claiming the upper bound is exclusive for `..` (that's `until`, a sibling topic).
  • Writing `1..10 in x` with operands reversed.
  • Thinking `1.5 in 1..10` compiles.

context