如何使用 Stream API 将字符串列表中的数据转换为 Map<String, Integer>?

How to convert data from the List of strings into a Map<String, Integer> with Stream API?

我尝试使用 Stream API.

将数据从 list 字符串转换为 Map<String, Integer>

但是我的做法不对:

public static Map<String, Integer> converter (List<String> data){
        return data.stream().collect(Collectors.toMap(e->e, Function.identity()));

如果我们有List.of("5", "7", "5", "8", "9", "8")

task №1作为键-String,值-字符频率

task №2作为键-String,值-字符串转换为整数

像这样尝试一个频率。请注意,地图不能有重复的键。

List<String> list2 = List.of("5", "7", "5", "8", "9","8");
  • keyString
  • value 开始 1
  • Integers::sum 每次出现都会添加 1
Map<String, Integer> freq = list2.stream().collect(Collectors.toMap(
         e->e, (a)->1, Integer::sum));

freq.entrySet().forEach(System.out::println);

打印

5=2
7=1
8=2
9=1

对于第二个任务,将字符串转换为 ints 是微不足道的。但请记住,重复项不存在,因此必须正确合并它们。这类似于第一个任务,除了我们只是转换为整数而不是计数。由于您有重复的整数,因此您需要提供 说明 说明如何操作。那就是 merge 函数 (a,b)->a 表示现有值 a 和新值 b,只需保持 a

List<String> list2 = List.of("5", "7", "5", "8", "9","8");
Map<String, Integer> map = list2.stream().collectCollectors.toMap(e->e,
              Integer::valueOf,
              (a,b)->a); // just keep the first one

打印

5=5
7=7
8=8
9=9

task №1 as key - String, and value - character frequency

为了获得每个字符的频率,您需要展平列表中的每个字符串(即拆分每个字符串转换为字符).

因为 Java 9 我们可以使用方法 chars() 其中 returns 用 int 原语表示的字符流。

flatMapToInt(String::chars) 将生成一个 IntStream,包含给定列表中每个字符串的字符。

然后 mapToObj() 为每个流元素创建一个 single-character 字符串。

要生成频率图,我们可以使用收集器 Collectors.groupingBy()Function.identity() 用作第一个参数,相当于 e -> e,它只是一种告诉流元素将用作 key 的方式,无需任何更改。第二个参数是 下游收集器 Collectors.counting(),它生成映射到特定 key.

的元素数量
public static Map<String, Long> getCharacterFrequency(List<String> list) {
    return list.stream()                               // Stream<String>
            .flatMapToInt(String::chars)               // IntStream
            .mapToObj(ch -> String.valueOf((char) ch)) // String<String>
            .collect(Collectors.groupingBy(Function.identity(),
                                           Collectors.counting()));
}

task №2 as key - String, and value - string converted to integer

您可以通过使用需要三个参数的 collector Collectors.toMap() 风格来实现:

  • keyMapper - 从流元素生成 key 的函数;
  • valueMapper - 从流元素生成 value 的函数;
  • mergeFunction - 一个函数,用于确定当两个值恰好映射到同一个键时如何解决这种情况。

虽然下面代码中的mergeFunction没有做任何特殊的事情,但还是需要提供,否则第一次遇到duplicate会导致IllegalStateException

public static Map<String, Integer> getStringValuesMappedToInts(List<String> list) {
    return list.stream()
            .collect(Collectors.toMap(Function.identity(), // key (String)
                                      Integer::valueOf,   // value (Integer)
                                      (v1, v2) -> v1));    // function that resolves collisions
}

main() - 演示

public static void main(String[] args) {
    List<String> source = List.of("5", "7", "57", "59", "5", "8", "99", "9", "8");
    // task 1
    System.out.println("task 1:\n" + getCharacterFrequency(source));
    // task 2
    System.out.println("task 2:\n" + getStringValuesMappedToInts(source));
}

输出

task 1:
{5=4, 7=2, 8=2, 9=4}
task 2:
{99=99, 57=57, 59=59, 5=5, 7=7, 8=8, 9=9}