我有地图地图
siteId -> (AppName -> App)
我想迭代内部地图中的所有应用并创建
的新地图(appId -> App)
我没有流
Map<String, App> result = new HashMap<>();
siteIdToAppNameToAppMap.forEach((siteId, map) ->
map.forEach((appName, app) ->
result.put(app.token, app)
)
);
我如何使用流?
答案 0 :(得分:4)
这样的事情怎么样?
siteIdToAppNameToAppMap.values()
.stream()
.flatMap(m -> m.values().stream())
.collect(
Collectors.toMap(App::getToken, Function.identity())
);
我们需要使用Stream#flatMap从嵌套地图中提取App
。所以stream().values()
会给我们Stream<Map<AppName,App>>
现在我们需要使用flatMap将其转换为Stream<App>
:
Stream<Map<AppName,App>> -> flatMap -> Stream<App>
之后我们终于可以收集到新的Map<AppId,App>
答案 1 :(得分:3)
与@Anton Balaniuc的回答略有不同。
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));
此解决方案根据siteIdToAppNameToAppMap
地图值创建一个流,然后我们对地图值执行map
操作,产生Stream<Collection<App>>
,然后flatMap
将全部折叠嵌套Stream<Collection<App>>
到Stream<App>
,最后toMap
收集器将返回一个Collector
,它将元素累积到一个Map中,其键的返回值为{{1} }和值是App::getToken
的返回值。
上面的函数Function.identity()
是合并函数,用于解决与同一个键关联的值之间的冲突。在这种特殊情况下,你不需要它,但它只是那里,所以我们可以使用(left, right) -> { throw new RuntimeException("duplicate key");}
收集器的这个重载,然后允许我们指定我们特别想要一个toMap
实例。
全部,其他HashMap
重载不保证返回的Map的类型,可变性,可序列化或线程安全性。
注意 - 如果你不期望重复的密钥然后抛出异常,如上所示,那就是要走的路,因为它表明存在问题而不是做其他事情。但是,如果在重复键的情况下您想要返回一个值,那么您可以根据需要将合并函数更改为toMap
或(left, right) -> left
。