Java流映射的映射列表



我有一个看起来像这样的实体:

public class Snippet {
private Integer docId;
private Integer page;
private Payload payload;
}

输入数据为List<Snippet>

我需要创建一个索引,它允许我们遍历docid和页面,并获得相关的Snippet对象。

所以像这样的数据结构:

Map<Integer, Map<Integer, List<Snippet>>>

我可以使用Java流来获取Map<Integer,>>-但这不会收集最后的片段列表。

List<Snippet> input = ....;
input.stream()
.collect(Collectors.groupingBy(
Snippet::getDocId, 
Collectors.toMap(Snippet::getPage, Function.identity())
)
);

如何进行收集以获得List作为最终映射值?

可以看到,Collectors.groupingBy(..)作为第二个参数获得collector。因此,只使用Collectors.groupingBy(..)作为Collectors.groupingBy(..)

的第二个参数
input.stream().collect(Collectors.groupingBy(
Snippet::getDocId,
Collectors.groupingBy(Snippet::getPage,
Collectors.toList())));

这是您当前或将来考虑的另一种选择。它使用Map接口的computeIfAbsent方法。

  • 创建最终内容映射。
  • 遍历Snippets
  • 列表
  • 如果DocId不存在,则创建以DocId为键的条目。然后尝试存储pageSnippet
  • 如果page不存在,则以page作为键创建条目。然后将Snippet存储在列表中。

下面是一个使用记录代替类的例子。

record PayLoad(String getValue) {
@Override
public String toString() {
return "[" + getValue() + "]";
}
}
record Snippet(int getDocId, int getPage,
PayLoad getPayLoad) {
@Override
public String toString() {
return String.format("{%s, %s, %s}", getDocId,
getPage, getPayLoad);
}
}

创建一些数据

List<Snippet> input =
List.of(new Snippet(1, 1, new PayLoad("A")),
new Snippet(1, 2, new PayLoad("B")),
new Snippet(1, 3, new PayLoad("C")),
new Snippet(2, 1, new PayLoad("D")),
new Snippet(2, 2, new PayLoad("E")),
new Snippet(2, 3, new PayLoad("F")));

存储代码片段

Map<Integer, Map<Integer, List<Snippet>>> map =
new HashMap<>();
for (Snippet s : input) {
map.computeIfAbsent(s.getDocId(), v -> new HashMap<>())
.computeIfAbsent(s.getPage(),
v -> new ArrayList<>())
.add(s);
}

打印他们

map.forEach((k, v) -> {
System.out.println(k);
v.forEach((kk, vv) -> System.out
.println("          " + kk + " -> " + vv));
});

打印

1
1 -> [{1, 1, [A]}]
2 -> [{1, 2, [B]}]
3 -> [{1, 3, [C]}]
2
1 -> [{2, 1, [D]}]
2 -> [{2, 2, [E]}]
3 -> [{2, 3, [F]}]