Categories

## Getting a Ratio Using a Single Iteration

Recently I came across the question of how to calculate the ratio of elements of a stream to the total number of elements in said stream. The naïve solution would be:

```collection.stream()
.filter(it -> it.completed())
.count() / collection.size()
```

However, depending on where `collection` came from this might iterate it twice, producing unnecessary load or I/O while doing so. Also, we would need to cast one of the two values to a `double` otherwise your result would be 0 pretty much all the time.

This is very ugly.

One possible solution is to use a `Collector` to do the ratio calculation for us. For this we would need a `Collector` that keeps track of the total number of elements and the number of elements that are completed. Lucky for us there is such a `Collector` already: the averaging collector. If we map all completed elements to a 1 and all not-completed elements to a 0, the result of the average will match the ratio we are expecting:

```collection.stream()
.collect(Collectors.averagingInt(it -> it.completed() ? 1 : 0));
```

In Kotlin, there is an `average` function defined on `Iterable<Int>` so you can do something very similar:

```collection.map { if (it.completed()) 1 else 0 }.average()
```

You could even combine that with an extension method and turn it into:

```collection.map(Foo::toCompletion).average()
…
private fun Foo.toCompletion() =
if (completed()) 1 else 0
```