In a when statement, it's possible to check if a v...
# getting-started
m
In a when statement, it's possible to check if a value is in a range. But is it possible to check for inequality (i.e. inclusion in an unbounded range)? This obviously won't work:
The alternative is to include the value in the comparison, but that forces me to also include it in range checks.
👍 1
e
as a workaround you can add the endpoints (since it's finite)
Copy code
when (value) {
    in Int.MIN_VALUE..1 -> "low"
    in 2..9 -> "middle"
    in 10..Int.MAX_VALUE -> "high"
or define your own
Copy code
value class LessThanOrEqualTo(val endInclusive: Int) {
    operator fun contains(value: Int): Boolean = value <= endInclusive
}

when (value) {
    in LessThanOrEqualTo(1) -> "low"
but either way you'll run into the issue of https://youtrack.jetbrains.com/issue/KT-8781
m
Including the other part of the range would add boilerplate to this. I want to avoid repeating "value" on each line:
b
Another possibility in that case is creating a
Map<Int, Color>
and rounding values?
e
or a
List<Color>
, you just have to take a little bit of care in handling rounding
in theory you could unroll it to a binary search instead of a linear search too 😛
🧠 2
m
Out of all solutions, this is certainly... one of them.
😁 6
I suddenly appreciate my when statement. 😄
😉 5
a
Is there any YouTrack proposal for adding
<
and
>
and other operators inside
when
statements ?
e
I don't think I've seen one, https://youtrack.jetbrains.com/issue/KT-28359 is the closest I know of
👍 2
k
You can probably do something with
SortedMap
. Example:
Copy code
val numberToSize = sortedMapOf(
        Comparator.reverseOrder(),
        0.0 to "XS", // 0.0 to 0.2499999...
        0.25 to "S", // 0.25 to 0.499999...
        0.5 to "M",
        0.7 to "L"
    )
    val size = numberToSize.tailMap(number).values.first()
e
I'd worry about what that does with NaN since it can't be fully ordered
whereas you can set up
Copy code
listOf(
     Color(0xFF2E74DF),
     Color(0xFF379CF6),
     Color(0xFF4ACFF3),
     Color(0xFF5CDCA6),
     Color(0xFF70E552),
     Color(0xFFEEFF83),
     Color(0xFFDC6C08),
     Color(0xFFCE4611),
     Color(0xFFBC1113),
     Color(0xFF6D231A),
).getOrElse(
    10 - (value.coerceIn(0.0, 1.0) * 10).toInt()
) { Color(0xFF8F3068) }
such that NaN falls into the expected bucket
k
That's good, as long as the choices have a regular step size. Using a map, you can have any step sizes. Also, you want something like
value.coerceIn(0.0, 1.0) * 10 + 0.5).toInt()
to avoid precision errors (e.g. 0.8 * 10 is 7.999...)
e
yeah just tested… NaN maps to the highest element in the SortedMap example, whereas it maps to the default element in Marcin's example and in my code
+ 0.5
shouldn't be used, that significantly changes where the boundaries are
I'm not sure where you're getting
0.8 * 10 = 7.999...
from, that's not the case
(true, that type of error could happen for other values, but not the ones mentioned here)
k
You're right, I was iterating from 0.0 to 1.0 stepping 0.1 and got to what I thought was 0.8 but was actually 0.7999...