将列表视为
id1_f, id2_d, id3_f, id1_g
,我如何使用流来获取<String, Integer>
格式的简化地图统计数据,例如:
id1 2
id2 1
id3 1
注:关键是
_
之前的部分。 reduce
函数可以帮忙吗?
这将完成工作:
Map<String, Long> map = Stream.of("id1_f", "id2_d", "id3_f", "id1_g")
.collect(
Collectors.groupingBy(v -> v.split("_")[0],
Collectors.counting())
);
您还可以使用
toMap
收集器:
myList.stream()
.collect(Collectors.toMap((String s) -> s.split("_")[0],
(String s) -> 1, Math::addExact);
如果您关心元素的顺序,请将结果转储到
LinkedHashMap
中。
myList.stream()
.collect(Collectors.toMap((String s) -> s.split("_")[0],
(String s) -> 1, Math::addExact,
LinkedHashMap::new));
使用 Map::merge:
的非流方法Map<String, Integer> result = new LinkedHashMap<>();
myList.forEach(s -> result.merge(s.split("_")[0], 1, Math::addExact));
既然你想要count元素,我建议使用Guava的
Multiset
界面,它专门用于此目的。
JavaDoc 中
Multiset
的定义:
支持与顺序无关的相等性的集合,如
,但可能有重复的元素。多重集有时也称为 bag。Set
多重集中彼此相等的元素被称为同一单个元素的“出现”。多重集中某个元素出现的总次数称为该元素的 count。
这里有两种使用方法:
1) 没有 Stream API:
ImmutableMultiset<String> multiset2 = ImmutableMultiset.copyOf(Lists.transform(
list, str -> StringUtils.substringBefore(str, "_")
));
2) 使用 Stream API:
ImmutableMultiset<String> multiset = list.stream()
.map(str -> StringUtils.substringBefore(str, "_"))
.collect(ImmutableMultiset.toImmutableMultiset());
请注意,我没有使用
s.split("_")[0]
之类的东西,而是使用了
Apache Commons Lang的
StringUtils.substringBefore
,我发现它更具可读性。您可以使用
方法检索元素的计数。