通过关联两个不同对象的两个 ID 创建一个集合
Create a collection by associating two id's of two different object
我有两个对象列表。
成员:列表,
成员历史:列表
这两个对象都有一个“id”字段。我想通过确保一个列表的“id”字段与具有相同 id 的另一个对象相关联,通过加入这两个列表来创建一个列表。两者,对象都有不同的数据,但它们是针对特定成员的。只需要以某种方式将它们配对以创建一个集合。
我开始了类似下面的事情。但是,我认为我需要先通过“id”映射它们,然后再压缩它们。谢谢!
members.zip(membersHistory).mapIndexed {_, pair ->
val (member, memberHistory) = pair
}
这里有几种创建项目对列表的方法。
- 对于第一个列表中的每个项目,在第二个列表中找到具有相同想法的对应项目,如果找到则将它们配对。
mapNotNull
将导致它跳过第二个列表中没有匹配项的项目。
val combination: List<Pair<Member, MemberHistory>> = members
.mapNotNull { member -> memberHistories.firstOrNull { it.id == member.id }?.let { member to it } }
- 要在 O(n) 中执行此操作,您可以使用
associateBy
.[=21 从其中一个源列表创建一个以 ID 作为键的映射=]
val memberHistoryById = memberHistories.associateBy { it.id }
val combination = members.mapNotNull { member -> memberHistoryById[member.id]?.let { member to it } }
据推测,虽然问题中没有明确说明,但id
是一个成员的ID,所以members
列表中不会有两个相同的对象id
值。
为了通过 ID 快速查找会员,我建议创建 2 个地图:
// Examples in Java
Map<Integer, Member> memberById = members.stream()
.collect(Collectors.toMap(Member::getId, Function.identity()));
Map<Integer, List<History>> memberHistoryById = membersHistory.stream()
.collect(Collectors.groupingBy(History::getId));
这些都很好保留,但如果您希望将成员和历史放在一起,则可以创建一个组合映射,由成员对象作为键控。假设 Member 的自然顺序是 而不是 ID,我们需要一个自定义键,我们可以用 TreeMap
.
Map<Member, List<History>> historyByMember = memberHistoryById.entrySet().stream()
.collect(Collectors.toMap(e -> memberById.get(e.getKey()),
Map.Entry::getValue,
(a,b) -> a/*this is never called*/,
() -> new TreeMap(Comparator.comparingInt(Member::getId)));
这个不错,使用映射将成员对象与其匹配的历史对象相关联。
写一个class
或者,您可以创建一个 class 将两个对象绑定在一起。
在 Java 16 及更高版本中,record 可能会。记录是编写 class 的一种简短方式,其主要目的是透明且不可变地传递数据。编译器隐式创建构造函数、getter、equals
& hashCode
和 toString
。一条记录可以在本地声明,也可以单独声明。
record MemberWithHistory ( Member member , History history ) {}
循环您的成员列表。
对于每个成员,找到匹配的历史记录。我们可以使用流轻松地做到这一点。制作一个历史对象流,过滤其成员标识符与第 n 个成员的标识符匹配的对象。如果找到,则返回 Optional
携带历史对象。否则,如果没有找到匹配的历史记录,则可选不携带任何内容。
如果可选确实有找到的历史对象,实例化一个新的MemberWithHistory
记录对象。通过添加到我们名为 mwhs
.
的结果列表来收集新记录
这里有一些未经测试的代码可以帮助您入门。
List< MemberWithHistory > mwhs = new ArrayList<>( members.size() ) ;
for( Member member : members )
{
Optional< History > historyOptional = histories.stream().filter( history -> history.memberId.equals( member.id ) ).findAny() ;
if( historyOptional.isPresent() )
{
MemberWithHistory mwh = new MemberWithHistory( member , historyOptional.get() ) ;
mwhs.add( mwh ) ;
}
}
如果您有大量项目,通过流重复搜索可能会变得低效。排序并可能从历史副本中删除可能更有效。但我不会为小数据量或偶尔使用而烦恼。
我有两个对象列表。
成员:列表, 成员历史:列表
这两个对象都有一个“id”字段。我想通过确保一个列表的“id”字段与具有相同 id 的另一个对象相关联,通过加入这两个列表来创建一个列表。两者,对象都有不同的数据,但它们是针对特定成员的。只需要以某种方式将它们配对以创建一个集合。
我开始了类似下面的事情。但是,我认为我需要先通过“id”映射它们,然后再压缩它们。谢谢!
members.zip(membersHistory).mapIndexed {_, pair ->
val (member, memberHistory) = pair
}
这里有几种创建项目对列表的方法。
- 对于第一个列表中的每个项目,在第二个列表中找到具有相同想法的对应项目,如果找到则将它们配对。
mapNotNull
将导致它跳过第二个列表中没有匹配项的项目。
val combination: List<Pair<Member, MemberHistory>> = members
.mapNotNull { member -> memberHistories.firstOrNull { it.id == member.id }?.let { member to it } }
- 要在 O(n) 中执行此操作,您可以使用
associateBy
.[=21 从其中一个源列表创建一个以 ID 作为键的映射=]
val memberHistoryById = memberHistories.associateBy { it.id }
val combination = members.mapNotNull { member -> memberHistoryById[member.id]?.let { member to it } }
据推测,虽然问题中没有明确说明,但id
是一个成员的ID,所以members
列表中不会有两个相同的对象id
值。
为了通过 ID 快速查找会员,我建议创建 2 个地图:
// Examples in Java
Map<Integer, Member> memberById = members.stream()
.collect(Collectors.toMap(Member::getId, Function.identity()));
Map<Integer, List<History>> memberHistoryById = membersHistory.stream()
.collect(Collectors.groupingBy(History::getId));
这些都很好保留,但如果您希望将成员和历史放在一起,则可以创建一个组合映射,由成员对象作为键控。假设 Member 的自然顺序是 而不是 ID,我们需要一个自定义键,我们可以用 TreeMap
.
Map<Member, List<History>> historyByMember = memberHistoryById.entrySet().stream()
.collect(Collectors.toMap(e -> memberById.get(e.getKey()),
Map.Entry::getValue,
(a,b) -> a/*this is never called*/,
() -> new TreeMap(Comparator.comparingInt(Member::getId)));
写一个class
或者,您可以创建一个 class 将两个对象绑定在一起。
在 Java 16 及更高版本中,record 可能会。记录是编写 class 的一种简短方式,其主要目的是透明且不可变地传递数据。编译器隐式创建构造函数、getter、equals
& hashCode
和 toString
。一条记录可以在本地声明,也可以单独声明。
record MemberWithHistory ( Member member , History history ) {}
循环您的成员列表。
对于每个成员,找到匹配的历史记录。我们可以使用流轻松地做到这一点。制作一个历史对象流,过滤其成员标识符与第 n 个成员的标识符匹配的对象。如果找到,则返回 Optional
携带历史对象。否则,如果没有找到匹配的历史记录,则可选不携带任何内容。
如果可选确实有找到的历史对象,实例化一个新的MemberWithHistory
记录对象。通过添加到我们名为 mwhs
.
这里有一些未经测试的代码可以帮助您入门。
List< MemberWithHistory > mwhs = new ArrayList<>( members.size() ) ;
for( Member member : members )
{
Optional< History > historyOptional = histories.stream().filter( history -> history.memberId.equals( member.id ) ).findAny() ;
if( historyOptional.isPresent() )
{
MemberWithHistory mwh = new MemberWithHistory( member , historyOptional.get() ) ;
mwhs.add( mwh ) ;
}
}
如果您有大量项目,通过流重复搜索可能会变得低效。排序并可能从历史副本中删除可能更有效。但我不会为小数据量或偶尔使用而烦恼。