我有一个看起来像这样的实体:
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
为键的条目。然后尝试存储page
和Snippet
- 如果
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]}]