流式处理两个集合,并基于公共属性收集一个映射



我四处找了一下,但没有找到一个优雅的解决方案。我要做的是有一个很好的精简(双关语)的解决方案,从两个集合谁有1个共享属性(各种id)创建一个地图。映射应该是匹配对象的键值。我现在如何做到这一点是在集合1上的forEach和集合2上的foreEach中获得匹配的模型,然后对其进行操作。我想创建一个映射,然后分别对映射中的每一对进行操作。我试图想出一个简单的例子,使它更清楚一点。

data class FirstNameModel(val idNumber: String, val firstName: String)
data class LastNameModel(val idNumber: String, val lastName: String)
val randomFirstNameList = listOf(
FirstNameModel("5631ab", "Bob"),
FirstNameModel("ca790a", "George"),
FirstNameModel("j8f1sa", "Alice")
)
val randomLastNameList = listOf(
LastNameModel("j8f1sa", "Smith"),
LastNameModel("5631ab", "Johnson"),
LastNameModel("ca790a", "Takai")
)
// stream function to correctly create map (not just a null one like below).
val map: Map<FirstNameModel, LastNameModel>? = null
fun printIt() {
map?.forEach {
println("Name for id ${it.key.idNumber} is ${it.key.firstName} ${it.value.lastName}")
}
//    should print something like:
//            Name for id 5631ab is Bob Johnson
//            Name for id ca790a is George Takai
//            Name for id j8f1sa is Alice Smith
}

我现在一直在Kotlin中尝试这个,但它有时也在Java中使用,所以我对两者都很好奇。

这可以工作,包括@Sweeper(谢谢!)在问题下面的评论中提到的情况:

val map: Map<FirstNameModel, LastNameModel> = randomFirstNameList.map { it.idNumber }
.plus(randomLastNameList.map { it.idNumber })
.distinct()
.associate { idNumber ->
(randomFirstNameList.firstOrNull { it.idNumber == idNumber } ?: FirstNameModel(idNumber, "")) to
(randomLastNameList.firstOrNull { it.idNumber == idNumber } ?: LastNameModel(idNumber, ""))
}

但是引入一个数据类来保存结果可能是有意义的:

data class NameModel(val idNumber: String, val firstName: String, val lastName: String)
val map: List<NameModel> = randomFirstNameList.map { it.idNumber }
.plus(randomLastNameList.map { it.idNumber })
.distinct()
.map { idNumber ->
NameModel(
idNumber,
randomFirstNameList.firstOrNull { it.idNumber == idNumber }?.firstName ?: "",
randomLastNameList.firstOrNull { it.idNumber == idNumber }?.lastName ?: ""
)
}

输出(包括一个姓氏条目,没有对应的名字条目):

NameModel(idNumber=5631ab, firstName=Bob, lastName=Johnson)
NameModel(idNumber=ca790a, firstName=George, lastName=Takai)
NameModel(idNumber=j8f1sa, firstName=Alice, lastName=Smith)
NameModel(idNumber=999999, firstName=, lastName=NoFirstName)

附加备注:

如果两个列表非常大,重复的firstOrNull调用可能会增加时间消耗。在这种情况下,为名字和姓氏创建查找映射是有意义的:

val firstNameMap = randomFirstNameList.associate { it.idNumber to it.firstName }
val lastNameMap = randomLastNameList.associate { it.idNumber to it.lastName }
val map: List<NameModel> = randomFirstNameList.map { it.idNumber }
.plus(randomLastNameList.map { it.idNumber })
.distinct()
.map { idNumber ->
NameModel(
idNumber,
firstNameMap.getOrElse(idNumber) { "" },
lastNameMap.getOrElse(idNumber) { "" }
)
}