通过关联两个不同对象的两个 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 




}

这里有几种创建项目对列表的方法。

  1. 对于第一个列表中的每个项目,在第二个列表中找到具有相同想法的对应项目,如果找到则将它们配对。 mapNotNull 将导致它跳过第二个列表中没有匹配项的项目。
val combination: List<Pair<Member, MemberHistory>> = members
    .mapNotNull { member -> memberHistories.firstOrNull { it.id == member.id }?.let { member to it } }
  1. 要在 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 & hashCodetoString。一条记录可以在本地声明,也可以单独声明。

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 ) ;
    }
}

如果您有大量项目,通过流重复搜索可能会变得低效。排序并可能从历史副本中删除可能更有效。但我不会为小数据量或偶尔使用而烦恼。