将 List<TypeA> 转换为 Map<TypeA, List<TypeB>> 使用 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
Table A 和 B 之间的映射是一对多
What am I doing wrong?
aList.stream().filter(aVal -> a.getUuid().equals(aVal.getUuid()))
基本上 select 列表中的所有 A 个实例与当前实例的 uuid 相匹配。如果多个实例具有相同的 uuid,您将 select 多个 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)]
}
How to fix this, given "Query Result: A.id, A.name, b.id, b.name" ?
查看 Map.computeIfAbsent()
,它允许您在缺少列表时创建一个列表,return 新的或现有的地图,然后链接 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
两次并在 bListMap
中设置列表 bList
两次,因为您的密钥只是 A
本身。因此,由于它们是不同的对象实例,它们的标识不同,将它们用作键会导致不同的映射条目。这就是为什么你会得到:
{
A1(with uuid1) : bList1,
A2(with uuid1) : bList1
}
您可以做的是,从 aList
中获取 A 的不同 uuid 的列表。 forEach
uuid,做你之前做的事。当我们只查看一次带有 uuid
的 A 时,键 A
不会重复出现,它是最终 bListMap
中对应的列表 bList
。
让我们看看我们刚才讨论的更改后的实现:
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);
});
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
Table A 和 B 之间的映射是一对多
What am I doing wrong?
aList.stream().filter(aVal -> a.getUuid().equals(aVal.getUuid()))
基本上 select 列表中的所有 A 个实例与当前实例的 uuid 相匹配。如果多个实例具有相同的 uuid,您将 select 多个 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)]
}
How to fix this, given "Query Result: A.id, A.name, b.id, b.name" ?
查看 Map.computeIfAbsent()
,它允许您在缺少列表时创建一个列表,return 新的或现有的地图,然后链接 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
两次并在 bListMap
中设置列表 bList
两次,因为您的密钥只是 A
本身。因此,由于它们是不同的对象实例,它们的标识不同,将它们用作键会导致不同的映射条目。这就是为什么你会得到:
{
A1(with uuid1) : bList1,
A2(with uuid1) : bList1
}
您可以做的是,从 aList
中获取 A 的不同 uuid 的列表。 forEach
uuid,做你之前做的事。当我们只查看一次带有 uuid
的 A 时,键 A
不会重复出现,它是最终 bListMap
中对应的列表 bList
。
让我们看看我们刚才讨论的更改后的实现:
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);
});