std Java:
double d = collection.stream()
.mapToInt(v -> v.getNumber())
.average()
.orElse(0.0);
This is a nice way to avoid checking for corner cases (empty collection). There is no way to do this in Kotlin. average()
returns NaN
in case of a empty list.
May I suggest a extension function to Double/Float
:
fun Double.orElse(fallback:Double): Double = if (isNaN()) fallback else this
Alternatively add a averageOrNull()
method, which will return null instead of NaN
.
I’m not sure whether I agree with you on this one because the average
function returns NaN not only when the collection is empty but also when one (or more) of the elements in a non-empty collection is itself NaN.
An explicit check for emptiness does at least resolve this situation
If, notwithstanding this problem, a new extension function were introduced, I’d prefer a name such as orIfNaN
to be absolutely clear on why the fallback value was being used.
Incidentally, although it’s a bit verbose, you can do something like this just now:
val da = doubleArrayOf()
val av = da.map { it.toInt() }.average().run { if (isNaN()) 0.0 else this }
println(av) // 0.0
You can also do:
val average = list.average()
.takeIf { !it.isNaN() } ?: 0
1 Like
Although this is a bit off topic, @Eliote’s reply raises an interesting (and slightly unnerving) point about how the ‘elvis’ operator works.
I thought at first that - as written - the expression wouldn’t compile because takeIf
is returning a Double?
and 0
is an integer literal.
However, it does compile and returns Any
which means, of course, that you can’t perform any subsequent arithmetic operations on it without casting it to a numeric type first.
This problem disappears if you replace 0
with 0.0
. The elvis operator now returns Double as expected.
1 Like