首页 > 解决方案 > 使用 Java-Stream 将字符串转换为 Map 并在结果 Map 中重复值

问题描述

您能否帮我找到下一种情况的更好/更清洁的解决方案: Web 元素属性以字符串形式收集,格式为:

animation-delay:0s;animation-direction:normal;animation-duration:0s;

目标:创建属性及其值的 Map<String, String>。注意:在属性值中重复是可能的,例如“无”。

当前可行的解决方案:来自字符串的表单列表 -

List<String> list = Arrays.stream(attributes.split(";")).collect(Collectors.toList());
Map<String, String> map = new HashMap<>();
for (String s : list) map.put(s.split(":")[0], s.split(":")[1]);

但是可能只用一个流就可以得到相同的结果,但是重复存在问题。不在键中,这在 Map 中是不允许的,但在 Collect 操作期间仍然有可能作为键的重复值。例如 width 和 height 的值都可以是 100px 并且它会在流中产生异常。下面的解决方案 - 不起作用......

Arrays.stream(attributes.split(";"))
                .distinct()
                .map(entry -> entry.split(":"))
                .collect(Collectors.toMap(entry -> entry[0], entry -> entry[1]));

提前感谢您的帮助!

标签: javajava-stream

解决方案


这应该通过映射到表示键值对的某个对象来完成,在最简单的情况下,它可以是字符串的列表/数组,然后将这些对收集到Mapusing 中Collectors.toMap

String attributes = "width:100px;height:100px;animation-delay:0s;"
    + "animation-direction:normal;animation-duration:0s;font-family:Arial;"
    + "font-family:Helvetica;font-family:sans-serif";

Map<String, String> map = Arrays.stream(attributes.split(";"))
        .map(pair -> pair.split(":"))
        .filter(arr -> arr.length > 1) // keep only key:value pairs
        .collect(Collectors.toMap(
            arr -> arr[0], 
            arr -> arr[1], 
            (v1, v2) -> String.join(", ", v1, v2) // merge values if needed
            , LinkedHashMap::new // optional argument to keep insertion order
        ));

map.forEach((k, v) -> System.out.printf("%s: %s%n", k, v));

输出:

width: 100px
height: 100px
animation-delay: 0s
animation-direction: normal
animation-duration: 0s
font-family: Arial, Helvetica, sans-serif

地图也可以用Collectors.groupingBy++收集Collectors.mappingCollectors.joining

Map<String, String> map = Arrays.stream(attributes.split(";"))
        .map(pair -> pair.split(":"))
        .filter(arr -> arr.length > 1) // keep only key:value pairs
        .collect(Collectors.groupingBy(
            arr -> arr[0], 
            TreeMap::new, // optional, sort by keys
            Collectors.mapping(arr -> arr[1], Collectors.joining(", "))
        ));

输出:

animation-delay: 0s
animation-direction: normal
animation-duration: 0s
font-family: Arial, Helvetica, sans-serif
height: 100px
width: 100px

推荐阅读