我能找到的最接近的东西是zip,它几乎可以满足我的需求,但它使用了索引。如果两个列表的值相同,我想指定一个字段来连接它们。
在SQL中;table1 INNER JOIN table2 WHERE table1.field=table2.field";。科特林有类似的东西吗?
也许这个例子更清楚:
class Something(val id : Int, val value : Int)
val list1 = listOf(Something(0, 1), Something(1, 6), Something(2, 8))
val list2 = listOf(Something(1, 2), Something(5, 3), Something(9, 6))
val result = list1.innerJoin(list2, on=id).map { element1, element2 -> element1.value * element2.value}
//should return [12] (6*2)
list1和list2都有一个id为1的元素,因此在本例中,它们的值(6和2(相乘,结果应该是12。
目前我使用的是这个代码片段,它很有效,但我想知道是否有更简单、更有效的方法。
val result = list1.map { element1 ->
val element2 = list2.find { element2 -> element2.id == element1.id } ?: return@map null
element1.value * element2.value
}.filterNotNull()
谢谢。
您可以使用mapNotNull
来消除二次筛选步骤,但这几乎是您所能做到的最简洁的步骤。您也可以先将list2
转换为Map,将其从O(n^2(更改为O(n(。
val list2ById = list2.associateBy(Something::id)
val result = list1.mapNotNull { element1 ->
list2ById[element1.id]?.value?.times(element1.value)
}
Kotlin没有为此提供stdlib方法,但您可以定义自己的:
fun <T> Collection<T>.innerJoin(other: Collection<T>, on: T.() -> Any): Collection<Pair<T, T>> {
val otherByKey = other.associateBy(on)
return this.mapNotNull {
val otherMapped = otherByKey[on(it)]
if (otherMapped == null) null else it to otherMapped
}
}
用法:
fun main() {
val list1 = listOf(Something(0, 1), Something(1, 6), Something(2, 8))
val list2 = listOf(Something(1, 2), Something(5, 3), Something(9, 6))
val result = list1.innerJoin(list2, on = { id }).map { (element1, element2) -> element1.value * element2.value }
println(result) //12
}