繁体   English   中英

转换列表<TypeA>到地图<TypeA, List<TypeB> &gt; 使用 Java 8

[英]Convert List<TypeA> to Map<TypeA, List<TypeB>> using Java 8

class  A {
    private B b;
}
Map<A, List<B>> bListMap = new HashMap<>();

        aList.forEach(
                a-> {
                    
                    List<B> bList =
                            aList.stream().filter(aVal -> a.getUuid().equals(aVal.getUuid()))
                                          .map(A::getB)
                                          .collect(Collectors.toList());
                    bListMap.put(a, bList);
                });

出于某种原因,我在 bList 中多次获得相同的记录。

我究竟做错了什么?

旁注查询结果:A.id, A.name, b.id, b.name

表A和B之间的映射是一对多的

我究竟做错了什么?

aList.stream().filter(aVal -> a.getUuid().equals(aVal.getUuid()))基本上选择该列表中与当前实例的 uuid 匹配的所有A实例。 如果多个实例具有相同的 uuid,您将选择多个 B。 如果A没有适当的equals()hashCode()或者它们不只使用uuid ,您将使用 A 的每个单个实例作为映射键 - 因此两次获得“相同的 Bs 列表”。

示例:假设您获得以下 A 和 B id,并根据您的class A映射它们:

| A uuid | A instance | B id |
------------------------------
​| 1      | 0xCAFEBABE | 1    |
| 1      | 0x0BADBEEF | 2    |

现在,您的循环将为每个 A 收集 B id 的 1 和 2,但由于它们没有实例 ID(由 JVM 内部管理,基于内存地址),您将获得以下映射:

{ 
  A(1, 0xCAFEBABE)=[B(1), B(2)],
  A(1, 0x0BADBEEF)=[B(1), B(2)]
}
  

给定“查询结果:A.id,A.name,b.id,b.name”如何解决这个问题?

看看Map.computeIfAbsent() ,它允许您在缺少列表时创建列表,返回新的或现有的地图,然后链接 B 的添加。

类似于(此处为伪代码):

Map<Integer, A> aMap = ...

for(resultSet) {
   A a = aMap.computeIfAbsent(resultSet.aId, aId -> new A(aId, resultSet.aName));
   aToBMmap.computeIfAbsent( a, k -> new ArrayList<>())
       .add(new B(resultSet.bId, resultSet.bName));
)

好吧,您正在迭代aList每个元素,并从具有相同uuid的元素aList收集 B 的列表。

假设aList中的 5 个元素中有 2 个具有相同的 uuid(比如uuid1 )但不同的 B。比如一个有B1而另一个有B2 在这一部分:

aList.forEach(
            a-> {
                
                List<B> bList =
                        aList.stream().filter(aVal -> a.getUuid().equals(aVal.getUuid()))
                                      .map(A::getB)
                                      .collect(Collectors.toList());
                bListMap.put(a, bList);
            });

您正在尝试遍历 aList 中的每个A 所以,你会遍历了uuid1两次,设置列表bList两次在bListMap ,因为你的关键是什么,但A本身。 因此,由于它们是不同的对象实例,它们的身份是不同的,使用它们作为键会导致不同的映射条目。 这就是为什么你会得到:

{
    A1(with uuid1) : bList1,
    A2(with uuid1) : bList1
}

您可以做的是,从aList中获取 A 的不同 uuid 的列表。 forEach的UUID,做你前面做的事情。 当我们正在与一个看着uuid只有一次,就会有该键的重复次数A和它对应列表bList在最后bListMap 让我们看看我们刚刚讨论过的更改后的实现:

List<A> objAWithDistinctUuid = aList.stream()
            .filter(distinctByKey(A::getUuid))
            .collect(Collectors.toList());

objAWithDistinctUuid.stream().forEach(
            a -> {
                List<B> bList =
                        aList.stream().filter(aVal -> a.getUuid().equals(aVal.getUuid()))
                                .map(A::getB)
                                .collect(Collectors.toList());
                bListMap.put(a, bList);
            });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM