Mannie
Mannie

Reputation: 1664

filter a list to a certain size in Kotlin/Java

I'm looking for an most efficient way in Kotlin/Java to filter a List down by a certain count and with the removal of filtered elements being applied across the collection in a uniformed fashion (i.e. - the elements to be removed span across the entire collection evenly);

For Example

I came up with the following Kotlin extension function but it isn't working as expected (its return more than the requested count - e.g. initial size = 2593, newcount=125 - list=130)

fun <T> List<T>.filterDownByToCount(newCount: Int): List<T> {
    if (newCount < 0 || newCount >= this.size)
        throw IllegalArgumentException("prop ($newCount) must be between 1 and $newCount")
    val ratio = size / newCount
    val list = this.filterIndexed { index, _ -> index % ratio == 0 }
    return list
}

ideally this function can handle anything from 0 up to list.size-1 & I would like to use a library to do this (if possible) but can't seem to find any that fits my use case.

Upvotes: 0

Views: 1452

Answers (2)

Erwin Bolwidt
Erwin Bolwidt

Reputation: 31269

The problem is that the ratio is actually a fractional number, but you're doing integer arithmetic.

fun <T> List<T>.filterDownByToCount(newCount: Int): List<T> {
    if (newCount < 0 || newCount >= this.size)
        throw IllegalArgumentException("prop ($newCount) must be between 1 and $newCount")
    val ratio = size.toDouble() / newCount
    var accu = 0.0
    val list = this.filter { _ ->
        (accu <= 0).also { if (accu <= 0) accu += ratio; accu-- }
    }
    return list
}

You can change the ratio to be a Double - for your example, this returns a 125 element result.

Upvotes: 1

Andy Turner
Andy Turner

Reputation: 140319

The problem is that size / newCount is the floor of the ratio, so the ratio is too small, and hence you get more elements than you expect.

Use the ceiling instead:

val ratio = (size + newCount - 1) / newCount

For your example, this results in a list of size 124.

Upvotes: 1

Related Questions