Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a stream of the values in maps that are values in another map in Java

Sorry about the title of the question; it was kind of hard for me to make sense of it. If you guys have a better title, let me know and I can change it.

I have two types of objects, Bookmark and Revision. I have one large Map, like so:

Map<Long, Bookmark> mapOfBookmarks;

it contains key: value pairs like so:

1L: Bookmark1,
2L: Bookmark2,
...

Each Bookmark has a 'getRevisions()' method that returns a Map

public Map<Long, Revision> getRevisions();

I want to create a Stream that contains all revisions that exist under mapOfBookmarks. Essentially I want to do this:

List<Revision> revisions = new ArrayList<>();
for (Bookmark bookmark : mapOfBookmarks.values()) { // loop through each bookmark in the map of bookmarks ( Map<Long, Bookmark> )
    for (Revision revision : bookmark.getRevisions().values()) { // loop through each revision in the map of revisions ( Map<Long, Revision> )
        revisions.add(revision);  // add each revision of each map to the revisions list
    }
}
return revisions.stream(); // return a stream of revisions

However, I'd like to do it using the functionality of Stream, so more like:

return mapOfBookmarks.values().stream().everythingElseThatIsNeeded();

Which would essentially be like saying:

return Stream.of(revision1, revision2, revision3, revision4, ...);

How would I write that out? Something to note is that the dataset that it is looping through can be huge, making the list method a poor approach.

I'm using Windows 7 and Java 8

like image 858
user2869231 Avatar asked Mar 13 '23 00:03

user2869231


2 Answers

A flatmap is what you looking for. When you have streams contained within a stream that you wish to flatten, then flatmap is the answer,

List<Revision> all =
    mapOfBookmarks.values().stream()
        .flatMap(c -> c.getRevisions().values().stream())
        .collect(Collectors.toList());
like image 165
Sleiman Jneidi Avatar answered Apr 25 '23 12:04

Sleiman Jneidi


You are looking for the flatMap(mapper) operation:

Returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element.

In this case, we're making a Stream<Bookmark> by calling stream(), flat mapping it to the revisions of each bookmark and, finally, collecting that into a list with toList().

List<Revision> revisions = 
    mapOfBookmarks.values()
                  .stream()
                  .flatMap(bookmark -> boormark.getRevisions().values().stream())
                  .collect(Collectors.toList());

Note that your current code could also be improved by calling addAll instead of looping over each revisions:

for (Bookmark bookmark : mapOfBookmarks.values()) { // loop through each bookmark in the map of bookmarks ( Map<Long, Bookmark> )
    revisions.addAll(bookmark.getRevisions().values());
}
like image 22
Tunaki Avatar answered Apr 25 '23 12:04

Tunaki