【问题标题】:How to split a string into a map, grouping values by duplicate keys using streams?如何将字符串拆分为映射,使用流按重复键对值进行分组?
【发布时间】:2021-05-09 07:21:58
【问题描述】:

我想转换以下内容

String flString="view1:filedname11,view1:filedname12,view2:fieldname21";

Map<String,Set<String>> 获取键/值如下:

view1=[filedname11,filedname12]
view2=[fieldname21]

我想使用 Java 8 流。我试过了

Arrays.stream(tokens)
        .map(a -> a.split(":"))
        .collect(Collectors.groupingBy(
                a -> a[0], Collectors.toList()));

但是键也被添加到值列表中。

【问题讨论】:

    标签: java string java-8 java-stream key-value


    【解决方案1】:

    您应该使用Collectors::mapping 将数组映射到一个元素。

    String flString = "view1:filedname11,view1:filedname12,view2:fieldname21";
    
    Map<String, List<String>> map = Pattern.compile(",")
        .splitAsStream(flString)
        .map(a -> a.split(":"))
        .collect(
            Collectors.groupingBy(a -> a[0],
                Collectors.mapping(a -> a[1], Collectors.toList())
            )
        );
    
    map.entrySet().forEach(System.out::println);
    

    输出

    view1=[filedname11, filedname12]
    view2=[fieldname21]
    

    【讨论】:

      【解决方案2】:

      您可以使用Collectors#toMap(keyMapper,valueMapper,mergeFunction)方法如下:

      String flString = "view1:filedname11,view1:filedname12,view2:fieldname21";
      
      Map<String, Set<String>> map = Arrays
              .stream(flString.split(","))
              .map(str -> str.split(":"))
              .collect(Collectors.toMap(
                      arr -> arr[0],
                      arr -> new HashSet<>(Set.of(arr[1])),
                      (s1, s2) -> {
                          s1.addAll(s2);
                          return s1;
                      }));
      
      System.out.println(map);
      // {view1=[filedname11, filedname12], view2=[fieldname21]}
      

      【讨论】:

        【解决方案3】:

        当然@K.Nicholas 使用下游收集器的解决方案是完美的。

        但我另外创建了另一个也使用 Stream API 的替代解决方案。 它更复杂,会生成三个流,但也可以。

        String flString = "view1:filedname11,view1:filedname12,view2:fieldname21";
        
        Map<String, Set<String>> map1 =
                Arrays.stream(flString.split(","))
                        .map(a -> a.split(":"))
                        .collect(Collectors.toMap(
                                a -> a[0],
                                a -> a[1],
                                (a1, a2) -> a1 + "," + a2))
                        .entrySet().stream()
                        .collect(Collectors.toMap(
                                e -> e.getKey(),
                                e -> Arrays.stream(e.getValue().split(","))
                                        .collect(Collectors.toSet())));
        
        map1.entrySet().forEach(System.out::println);
        

        【讨论】:

          【解决方案4】:

          您可以使用以下代码实现您的目标:

          String flString = "view1:filedname11,view1:filedname12,view2:fieldname21";
          Map<String, List<String>> collect = Stream.of(flString)
                  .flatMap(str -> Stream.of(str.split(",")))
                  .map(keyValuePair -> keyValuePair.split(":"))
                  .collect(Collectors.groupingBy(it -> it[0], Collectors.mapping(it -> it[1], Collectors.toList())));
          

          简单的输出:

          {view1=[filedname11, filedname12], view2=[fieldname21]}
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-12-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多