Java 将字符串集合缩减为出现映射

Java reduce a collection of string to a map of occurence

将列表视为 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));

既然你想计数元素,我建议使用专用于此目的的Guava's Multiset接口。

JavaDoc 中 Multiset 的定义:

A collection that supports order-independent equality, like Set, but may have duplicate elements. A multiset is also sometimes called a bag.

Elements of a multiset that are equal to one another are referred to as occurrences of the same single element. The total number of occurrences of an element in a multiset is called the count of that element.

这里有两种使用方法:

1) 没有流 API:

ImmutableMultiset<String> multiset2 = ImmutableMultiset.copyOf(Lists.transform(
        list, str -> StringUtils.substringBefore(str, "_")
));

2) 使用流 API:

ImmutableMultiset<String> multiset = list.stream()
        .map(str -> StringUtils.substringBefore(str, "_"))
        .collect(ImmutableMultiset.toImmutableMultiset());

请注意,我没有使用 s.split("_")[0] 之类的东西,而是使用了 Apache Commons Lang's StringUtils.substringBefore,我发现它更具可读性。

您使用 Multiset.count() 方法检索元素的计数。