首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Java8: HashMap<X、Y>到HashMap<X、使用流/贴图-Reduce/收集器的Z>

Java8: HashMap<X、Y>到HashMap<X、使用流/贴图-Reduce/收集器的Z>
EN

Stack Overflow用户
提问于 2014-09-18 10:14:03
回答 9查看 208.2K关注 0票数 248

我知道如何从Y -> Z“转换”一个简单的Java List,即:

List<String> x;
List<Integer> 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示例一样,我想调用任何方法(或构造函数)。

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2014-09-18 10:21:18

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

它没有列表代码那么好。您不能在map()调用中构造新的Map.Entry,因此工作会混合到collect()调用中。

票数 439
EN

Stack Overflow用户

发布于 2014-09-18 14:00:11

这里有一些Sotirios Delimanolis' answer的变体,它从一开始就很好(+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);

(还有一个map值的示例,但它确实是人为设计的,我承认对Y使用有界通配符只在边缘情况下有帮助。)

第二点是,我在keySet上运行流,而不是在输入映射的entrySet上运行流。我认为,这使得代码更加简洁,但代价是必须从map中获取值,而不是从map条目中获取值。顺便说一句,我最初将key -> key作为toMap()的第一个参数,但由于某种原因导致类型推断错误而失败。就像Function.identity()一样,把它改成(X key) -> key也行。

还有另一种变体如下:

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()而不是streams。我认为这甚至更简单,因为它省去了收集器,因为收集器在使用地图时有点笨拙。原因是Map.forEach()将键和值作为单独的参数提供,而流只有一个值--您必须选择是使用键还是映射条目作为该值。不利的一面是,这缺乏其他方法丰富的、流畅的优点。:-)

票数 37
EN

Stack Overflow用户

发布于 2014-09-18 10:23:52

像这样的通用解决方案

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));
票数 16
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25903137

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档