我有一个列表,其中每个元素都是一个Map:
List< Map<String, List<String>> >
我想使用Java 8的特性将所有列表中的元素(即Map中的值)收集到一个单独的Set
中。
例如:
Input: [ {"a" : ["b", "c", "d"], "b" : ["a", "b"]}, {"c" : ["a", "f"]} ]
Output: ["a", "b", "c", "d", "f"]
谢谢。
我有一个列表,其中每个元素都是一个Map:
List< Map<String, List<String>> >
我想使用Java 8的特性将所有列表中的元素(即Map中的值)收集到一个单独的Set
中。
例如:
Input: [ {"a" : ["b", "c", "d"], "b" : ["a", "b"]}, {"c" : ["a", "f"]} ]
Output: ["a", "b", "c", "d", "f"]
List<Map<String, List<String>>> input = ...;
Set<String> output = input.stream() // -> Stream<Map<String, List<String>>>
.map(Map::values) // -> Stream<List<List<String>>>
.flatMap(Collection::stream) // -> Stream<List<String>>
.flatMap(Collection::stream) // -> Stream<String>
.collect(Collectors.toSet()) // -> Set<String>
;
使用flatMap
函数来实现该目的。
List< Map<String, List<String>> > maps = ...
Set<String> result = maps.stream()
.flatMap(m -> m.values().stream())
.flatMap(List::stream)
.collect(Collectors.toSet());
除了基于 .flatMap
的解决方案,另一种选择是将这些子迭代合并到最终的 collect
操作中:
Set<String> output = input.stream()
.collect(HashSet::new, (set,map) -> map.values().forEach(set::addAll), Set::addAll);
对于这个问题,有很多解决方案。以下是其中几种,包括使用Eclipse Collections容器提供的其他两个答案。
MutableList<MutableMap<String, MutableList<String>>> list =
Lists.mutable.with(
Maps.mutable.with(
"a", Lists.mutable.with("b", "c", "d"),
"b", Lists.mutable.with("a", "b")),
Maps.mutable.with(
"c", Lists.mutable.with("a", "f")));
ImmutableSet<String> expected = Sets.immutable.with("a", "b", "c", "d", "f");
// Accepted Streams solution
Set<String> stringsStream = list.stream()
.map(Map::values)
.flatMap(Collection::stream)
.flatMap(Collection::stream)
.collect(Collectors.toSet());
Assert.assertEquals(expected, stringsStream);
// Lazy Eclipse Collections API solution
MutableSet<String> stringsLazy = list.asLazy()
.flatCollect(MutableMap::values)
.flatCollect(e -> e)
.toSet();
Assert.assertEquals(expected, stringsLazy);
// Eager Eclipse Collections API solution
MutableSet<String> stringsEager =
list.flatCollect(
map -> map.flatCollect(e -> e),
Sets.mutable.empty());
Assert.assertEquals(expected, stringsEager);
// Fused collect operation
Set<String> stringsCollect = list.stream()
.collect(
HashSet::new,
(set, map) -> map.values().forEach(set::addAll),
Set::addAll);
Assert.assertEquals(expected, stringsCollect);
// Fused injectInto operation
MutableSet<String> stringsInject =
list.injectInto(
Sets.mutable.empty(),
(set, map) -> set.withAll(map.flatCollect(e -> e)));
Assert.assertEquals(expected, stringsInject);