如何使用Kotlin在原地过滤列表?

41

使用Java代码可以从列表中删除项目:

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

如何在 Kotlin 中实现相同的功能(即删除一个 List 中的一些项目而无需重新创建)?


3
只需将此代码复制到 Kotlin 文件中,IDE 将自动为您完成翻译。 - Sachin Chandil
3个回答

89

只需使用.retainAll { ... }.removeAll { ... },两者都接受一个谓词(predicate)来原地过滤(filter):

items.retainAll { shouldRetain(it) }

items.removeAll { shouldRemove(it) }
注意,为了实现这一点,items 应该是一个 MutableList<T>,而不仅仅是一个在 Kotlin 中只读的 List<T>,因此不会暴露任何更改函数(见语言参考中的 Collections)。
顺便提一下,如果列表支持随机访问,这两个函数将以高效方式实现:然后列表在每个项目被删除后不会被压缩(最坏情况下需要 O(n2) 时间),而是在处理列表时将项目移动到列表中,以达到 O(n) 的时间复杂度。
另外,如果您不想修改原始列表,可以使用 .filter { ... }.filterNot { ... } 生成仅包含您想要保留的项的单独集合,这对于只读的 List<T> 也适用。
val filtered = items.filter { shouldRetain(it) }

val filtered = items.filterNot { shouldRemove(it) }

4
如果没有这个功能,我会感到惊讶。标准库太棒了。 - zsmb13
1
你是不是想说 removeAll?因为在问题中,当谓词“通过”时,会删除一个项目。 - Ilya
@Ilya,谢谢,只是checkItem这个名称让我感到困惑。已经修复了。 - hotkey

5

Kotlin拥有许多方便的内置函数。在这里,您可以尝试使用filter

val filteredItems = items.filter { checkItem(it) }  

不幸的是,它会重新创建列表。这个API是有意设计成避免额外的可变性。

但是如果你仍然想要使用MutableList,请使用retainAll方法。

items.retainAll { checkItem(it) }

2
这将从1-9的列表中删除偶数,并打印出[1, 3, 5, 7, 9]。最初的回答。
var myLists = mutableListOf(1,2,3,4,5,6,7,8,9)
myLists.removeAll{ it % 2 == 0 }
println(myLists)

这将保留列表1-9中的偶数并删除其他数字,输出[2, 4, 6, 8]作为最初的回答。
myLists = mutableListOf(1,2,3,4,5,6,7,8,9)
myLists.retainAll{ it % 2 == 0 }
println(myLists)

https://play.kotlinlang.org/上尝试它们。最初的回答。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接