【问题标题】:Make a new list from two other lists of different types by comparing values of each type通过比较每种类型的值,从其他两个不同类型的列表中创建一个新列表
【发布时间】:2017-12-02 11:48:43
【问题描述】:

我有两个对象列表,它们都实现了一个接口,但在其他方面不相关。如何创建一个新的对象集合,其中只包含一个列表中与另一个列表中的值匹配的对象?

显然我可以使用 for 循环并手动执行此操作,但我想知道如何使用 Kotlin 的标准库集合过滤函数来执行此操作。

下面是一个例子:

interface Ids
{
    val id: Int
}

data class A(override val id: Int, val name: String) : Ids
data class B(override val id: Int, val timestamp: Long) : Ids

fun main(args: Array<String>) {
    val a1 = A(1, "Steve")
    val a2 = A(2, "Ed")
    val aCol = listOf(a1, a2)

    val b2 = B(2, 12345)
    val b3 = B(3, 67890)
    val bCol = listOf(b2, b3)

    val matches = mutableListOf<B>()
    // This is where I'm stuck.
    // I want to filter bCol using objects from aCol as a filter.
    // The result should be that matches contains only a single object: b2
    // because bCol[0].id == aCol[1].id
    // I'm guessing I need to start with something like this:
    bCol.filterTo(matches) { ??? }
}

【问题讨论】:

    标签: list kotlin filtering


    【解决方案1】:

    一种简单的方法是在aCol 中搜索bCol 中每个b 具有相同ID 的对象:

    bCol.filter { b -> aCol.any { a -> a.id == b.id } }
    

    但是,如果您的列表足够大,这可能会变得太慢。

    为了使其更具可扩展性,您可以首先在 aCol 中构建一组所有 id:

    val aColIds = aCol.map { it.id }.toSet()
    

    然后使用Set.contains方法判断b.id是否在aColIds中:

    bCol.filter { it.id in aColIds }
    // or equivalent
    bCol.filter { aColIds.contains(it.id) }
    

    【讨论】:

    • 我最终得到了这个做我想做的事:bCol.filterTo(matches) { aCol.map { it.id }.contains(it.id)}。关于这如何影响性能与您的答案的任何想法?在这个特定的例子中,我永远不会有一个非常大的数据集(
    • @JordanBondo 这比第一种方法还要慢,因为aCol.map 会为bCol 中的每个项目调用,然后结果被丢弃。因此,它不仅会增加计算复杂度,还会增加显着的内存成本。
    • 对于遇到此问题的其他人,我对大型(100 万)和小型(256)数据集进行了一些测试,发现虽然@Ilya 的解决方案确实比我的解决方案快得多,但使用filterTo 而不是比filter 也有显着的性能提升。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-12
    • 1970-01-01
    • 1970-01-01
    • 2019-04-22
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    相关资源
    最近更新 更多