I have an entity that looks like this:
public class Snippet {
private Integer docId;
private Integer page;
private Payload payload;
}
The input data is a List<Snippet>
I need to create an index that allows us to iterate over docIds and pages and obtain the associated Snippet objects.
So a data structure like this:
Map<Integer, Map<Integer, List<Snippet>>>
I can use Java streams to get a Map<Integer, Map<Integer, Snippet>> - but this won't collect the list of Snippets at the end.
List<Snippet> input = ....;
input.stream()
.collect(Collectors.groupingBy(
Snippet::getDocId,
Collectors.toMap(Snippet::getPage, Function.identity())
)
);
How can I do the collecting to get a List as the final map value?
CodePudding user response:
As you can see, Collectors.groupingBy(..)
gets collector as 2nd argument. So, just use Collectors.groupingBy(..)
as 2nd argument of Collectors.groupingBy(..)
input.stream().collect(Collectors.groupingBy(
Snippet::getDocId,
Collectors.groupingBy(Snippet::getPage,
Collectors.toList())));
CodePudding user response:
Here is another alternative for your current or future consideration. It uses the computeIfAbsent
method of the Map Interface.
- create the final content map.
- iterate thru the list of
Snippets
- if the
DocId
is not present, create the entry withDocId
as key. Then try and store thepage
andSnippet
- if the
page
is not present, create the entry withpage
as key. Then store theSnippet
in the list.
Here is an example using records in place of classes.
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);
}
}
Create some data
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")));
Store the snippets
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);
}
Print them
map.forEach((k, v) -> {
System.out.println(k);
v.forEach((kk, vv) -> System.out
.println(" " kk " -> " vv));
});
prints
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]}]