Java8:HashMap <X,Y>到HashMap <X,Z>使用Stream/Map-Reduce/Collector

 毛小猫TTN 发布于 2022-12-20 19:02

我知道如何ListY- > "转换"一个简单的Java Z,即:

List x;
List y = x.stream()
        .map(s -> Integer.parseInt(s))
        .collect(Collectors.toList());

现在我想用Map做基本相同的事情,即:

INPUT:
{
  "key1" -> "41",    // "41" and "42"
  "key2" -> "42      // are Strings
}

OUTPUT:
{
  "key1" -> 41,      // 41 and 42
  "key2" -> 42       // are Integers
}

解决方案不应限于String- > Integer.就像List上面的例子一样,我想调用任何方法(或构造函数).

6 个回答
  • Map<String, String> x;
    Map<String, Integer> y =
        x.entrySet().stream()
            .collect(Collectors.toMap(
                e -> e.getKey(),
                e -> Integer.parseInt(e.getValue())
            ));
    

    它不如列表代码那么好.您无法Map.Entrymap()呼叫中构建新的s,因此工作会混合到collect()呼叫中.

    2022-12-20 19:03 回答
  • Guava的功能Maps.transformValues是你正在寻找的,它与lambda表达式很好地配合:

    Maps.transformValues(originalMap, val -> ...)
    

    2022-12-20 19:04 回答
  • 以下是Sotirios Delimanolis回答的一些变化,这一点非常好(+1).考虑以下:

    static <X, Y, Z> Map<X, Z> transform(Map<? extends X, ? extends Y> input,
                                         Function<Y, Z> function) {
        return input.keySet().stream()
            .collect(Collectors.toMap(Function.identity(),
                                      key -> function.apply(input.get(key))));
    }
    

    这里有几点.首先是在泛型中使用通配符; 这使得功能更加灵活.例如,如果您希望输出映射具有输入映射键的超类的键,则需要使用通配符:

    Map<String, String> input = new HashMap<String, String>();
    input.put("string1", "42");
    input.put("string2", "41");
    Map<CharSequence, Integer> output = transform(input, Integer::parseInt);
    

    (地图的值也有一个例子,但它确实是人为的,我承认Y的有界通配符只对边缘情况有帮助.)

    第二点是,而不是运行在输入地图的流entrySet,我跑过来的keySet.我认为,这使得代码更加清晰,代价是必须从地图而不是地图条目中获取值.顺便说一句,我最初key -> key作为第一个参数,toMap()由于某种原因,它因类型推断错误而失败.把它(X key) -> key改成工作,就像那样Function.identity().

    还有另一种变化如下:

    static <X, Y, Z> Map<X, Z> transform1(Map<? extends X, ? extends Y> input,
                                          Function<Y, Z> function) {
        Map<X, Z> result = new HashMap<>();
        input.forEach((k, v) -> result.put(k, function.apply(v)));
        return result;
    }
    

    这使用Map.forEach()而不是流.我认为这更简单,因为它省去了收藏家,这些收藏家与地图一起使用有些笨拙.原因是Map.forEach()将键和值作为单独的参数,而流只有一个值 - 您必须选择是使用键还是映射条目作为该值.从缺点来看,这缺乏其他方法的丰富,流动的优点.:-)

    2022-12-20 19:04 回答
  • 我的StreamEx库增强了标准流API,提供了一个EntryStream更适合转换地图的类:

    Map<String, Integer> output = EntryStream.of(input).mapValues(Integer::valueOf).toMap();
    

    2022-12-20 19:04 回答
  • 像这样的通用解决方案

    public static <X, Y, Z> Map<X, Z> transform(Map<X, Y> input,
            Function<Y, Z> function) {
        return input
                .entrySet()
                .stream()
                .collect(
                        Collectors.toMap((entry) -> entry.getKey(),
                                (entry) -> function.apply(entry.getValue())));
    }
    

    Map<String, String> input = new HashMap<String, String>();
    input.put("string1", "42");
    input.put("string2", "41");
    Map<String, Integer> output = transform(input,
                (val) -> Integer.parseInt(val));
    

    2022-12-20 19:04 回答
  • 它绝对必须100%功能和流畅吗?如果没有,那么这个怎么样,就像它得到的一样短:

    Map<String, Integer> output = new HashMap<>();
    input.forEach((k, v) -> output.put(k, Integer.valueOf(v));
    

    (如果你能忍受将流与副作用结合起来的羞耻感和内疚感)

    2022-12-20 19:04 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有