Java/Kotlin如何流式处理两个共有ID属性的集合生成匹配对象Map
问题说明
- 需求:通过简洁的流式处理方案,对两个共有同ID属性的集合做关联匹配,生成键值对为<第一个集合元素, 第二个集合匹配元素>的Map,替代嵌套双重forEach的低效率写法,后续可直接对生成的Map执行批量业务操作。
- 示例基础代码:
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 }
实现方案
核心思路:先对被关联的集合(即LastNameModel集合)按共有ID建立哈希索引,将单次ID查询的时间复杂度降到O(1),整体关联逻辑时间复杂度从双重循环的O(n*m)降到O(n+m),全流程采用流式链式调用,逻辑清晰易维护。
Kotlin 实现
直接使用Kotlin标准库提供的集合操作函数即可完成,不需要额外依赖:
// 1. 先将LastName集合按idNumber建立哈希索引 val lastNameIndex = randomLastNameList.associateBy { it.idNumber } // 2. 流式关联生成目标Map,自动过滤无匹配ID的项 val map: Map<FirstNameModel, LastNameModel> = randomFirstNameList .mapNotNull { firstItem -> lastNameIndex[firstItem.idNumber]?.let { matchedLast -> firstItem to matchedLast } } .toMap() fun printIt() { map.forEach { println("Name for id ${it.key.idNumber} is ${it.key.firstName} ${it.value.lastName}") } }
执行printIt()将输出预期结果:
Name for id 5631ab is Bob Johnson Name for id ca790a is George Takai Name for id j8f1sa is Alice Smith
- 如果需要保留ID不匹配的项(值为null),将
mapNotNull替换为map,取值逻辑改为lastNameIndex[firstItem.idNumber]即可。
Java 实现
基于Java 8及以上版本的Stream API实现,逻辑和Kotlin版本一致:
import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; // 模型类 class FirstNameModel { private String idNumber; private String firstName; public FirstNameModel(String idNumber, String firstName) { this.idNumber = idNumber; this.firstName = firstName; } public String getIdNumber() { return idNumber; } public String getFirstName() { return firstName; } } class LastNameModel { private String idNumber; private String lastName; public LastNameModel(String idNumber, String lastName) { this.idNumber = idNumber; this.lastName = lastName; } public String getIdNumber() { return idNumber; } public String getLastName() { return lastName; } } public class MatchDemo { public static void main(String[] args) { List<FirstNameModel> randomFirstNameList = List.of( new FirstNameModel("5631ab", "Bob"), new FirstNameModel("ca790a", "George"), new FirstNameModel("j8f1sa", "Alice") ); List<LastNameModel> randomLastNameList = List.of( new LastNameModel("j8f1sa", "Smith"), new LastNameModel("5631ab", "Johnson"), new LastNameModel("ca790a", "Takai") ); // 1. 构建LastName集合的ID索引,指定重复key的合并策略避免报错 Map<String, LastNameModel> lastNameIndex = randomLastNameList.stream() .collect(Collectors.toMap( LastNameModel::getIdNumber, Function.identity(), (oldVal, newVal) -> newVal )); // 2. 流式关联生成目标Map,过滤无匹配项 Map<FirstNameModel, LastNameModel> matchMap = randomFirstNameList.stream() .filter(first -> lastNameIndex.containsKey(first.getIdNumber())) .collect(Collectors.toMap( Function.identity(), first -> lastNameIndex.get(first.getIdNumber()) )); // 遍历输出 matchMap.forEach((key, value) -> { System.out.printf("Name for id %s is %s %s%n", key.getIdNumber(), key.getFirstName(), value.getLastName()); }); } }
- 如果需要保留ID不匹配的项,移除
filter步骤,取值时用lastNameIndex.getOrDefault(first.getIdNumber(), null)即可。
内容的提问来源于stack exchange,提问作者Bowerick
相关产品推荐
相关产品推荐

