How to filter a list in-place with Kotlin?

BArtWell picture BArtWell · Jun 21, 2017 · Viewed 14.6k times · Source

In Java I can remove items from a list with this code:

private void filterList(List<Item> items) {
    Iterator<Item> iterator = items.iterator();
    while (iterator.hasNext()) {
        if (checkItem(iterator.next())) {
            iterator.remove();
        }
    }
}

How to make the same in Kotlin (i.e. remove some items in a List without re-creation)?

Answer

hotkey picture hotkey · Jun 21, 2017

Just use .retainAll { ... } or .removeAll { ... }, both accepting a predicate, to filter it in-place:

items.retainAll { shouldRetain(it) }

items.removeAll { shouldRemove(it) }

Note that items should be a MutableList<T> for that, not just List<T>, which is a read-only list in Kotlin and thus does not expose any mutating functions (see: Collections in the language reference).

By the way, these two function are implemented efficiently for lists that support random access: then the list is not compacted after each item is removed (O(n2) time worst-case), and instead the items are moved within the list as it is processed, giving O(n) time.


And if you don't want to modify the original list, you can produce a separate collection with only the items you want to retain using .filter { ... } or .filterNot { ... }, this will work for read-only List<T> as well:

val filtered = items.filter { shouldRetain(it) }