流式传输两个集合并根据公共属性收集地图

问题描述 投票:0回答:1

我环顾四周,但没有找到一个优雅的解决方案。我想做的是有一个很好的简化(双关语)解决方案,从两个拥有 1 个共享属性(某种 id)的集合创建一个地图。映射应该是匹配对象的键值。

我现在的做法是在集合 1 上使用 forEach 并在集合 2 上使用 forEach 来获取匹配模型,然后对其进行操作。我想创建地图,然后分别对地图中的每一对进行操作。我试图举一个简单的例子来让它更清楚一些。

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 中使用这个用例,所以对两者都很好奇。

java kotlin collections java-stream
1个回答
1
投票

这将有效,包括问题下方@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) { "" }
    )
  }
© www.soinside.com 2019 - 2024. All rights reserved.