Java列表地图的流图

Java stream map of map of list

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

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

输入数据是List<Snippet>

我需要创建一个索引,使我们能够遍历 docId 和页面并获取关联的 Snippet 对象。

所以这样的数据结构:

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

我可以使用 Java 流来获取 Map> - 但最后不会收集 Snippet 列表。

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

如何收集得到一个列表作为最终的地图值?

如您所见,Collectors.groupingBy(..) 将收集器作为第二个参数。所以,只需使用 Collectors.groupingBy(..) 作为 Collectors.groupingBy(..)

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

这是您当前或未来考虑的另一种选择。它使用 Map Interface.

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]}]