Java 8 streams - How to extract all objects inside a map of maps to a new map?

不想你离开。 提交于 2019-12-10 10:04:59

问题


I have a map of maps

siteId -> (AppName -> App) 

I want to iterate all of the Apps in the inner map and create a new map of

(appId -> App)

I do it without stream

Map<String, App> result = new HashMap<>();

siteIdToAppNameToAppMap.forEach((siteId, map) ->
   map.forEach((appName, app) ->
      result.put(app.token, app)
   )
);

How do I do it with stream?


回答1:


What about something like this?

siteIdToAppNameToAppMap.values()
   .stream()
   .flatMap(m -> m.values().stream())
   .collect(
        Collectors.toMap(App::getToken, Function.identity())
   );

We will need to use Stream#flatMap to extract App from nested map. So stream().values() will give us Stream<Map<AppName,App>> now we need to transform it into Stream<App> using flatMap:

Stream<Map<AppName,App>> -> flatMap ->  Stream<App>

and after is we can finally collect to a new Map<AppId,App>




回答2:


A slightly different variant to @Anton Balaniuc's answer.

Map<String, App> resultSet = 
           siteIdToAppNameToAppMap.values()
                                  .stream()
                                  .map(Map::values)
                                  .flatMap(Collection::stream)
                                  .collect(Collectors.toMap(App::getToken, 
                                            Function.identity(), (left, right) -> {  
                                       throw new RuntimeException("duplicate key");
                                             },
                                                   HashMap::new));

This solution creates a stream from the siteIdToAppNameToAppMap map values, which we then perform a map operation to the map values yielding a Stream<Collection<App>> and then flatMap will collapse all the nested Stream<Collection<App>> to a Stream<App> and then finally the toMap collector will return a Collector that accumulates the elements into a Map whose keys are the return value of App::getToken and values are the return value of Function.identity().

The function (left, right) -> { throw new RuntimeException("duplicate key");} above is the merge function, used to resolve collisions between values associated with the same key. in this particular case, you don't need it but it's only there so we can use this overload of the toMap collector which then allows us to specify that we specifically want a HashMap instance.

All, the other toMap overloads don't guarantee on the type, mutability, serializability, or thread-safety of the Map returned.

Note - if you're not expecting duplicate keys then throwing an exception, as shown above, is the way to go as it indicates there's a problem as opposed to doing something else. However, if in the case of a duplicate key you want to return a value then you can simply change the merge function to (left, right) -> left or (left, right) -> right depending on what you want.



来源:https://stackoverflow.com/questions/49353493/java-8-streams-how-to-extract-all-objects-inside-a-map-of-maps-to-a-new-map

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!