当前位置: 首页 > 知识库问答 >
问题:

Java8:使用Stream/Map-Reduce/Collector将HashMap转换为HashMap

吴高畅
2023-03-14

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

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

现在我想用一张地图做基本相同的操作,即:

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

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

解决方案不应局限于字符串->整数。就像上面的list示例一样,我希望调用任何方法(或构造函数)。

共有3个答案

祁正阳
2023-03-14

类似这样的通用解决方案

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));
祁博涛
2023-03-14

下面是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()的第一个参数,但由于某种原因导致类型推断错误而失败。将其更改为(Xkey)->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()将键和值作为单独的参数给出,而流只有一个值--您必须选择是使用键还是映射条目作为该值。在缺点方面,这种方法缺乏其他html" target="_blank">方法的丰富、流畅的优点。:-)

太叔乐家
2023-03-14
Map<String, String> x;
Map<String, Integer> y =
    x.entrySet().stream()
        .collect(Collectors.toMap(
            e -> e.getKey(),
            e -> Integer.parseInt(e.getValue())
        ));

它不像列表代码那么好。您不能在map()调用中构造新的map.entrys,因此该工作被混合到collection()调用中。

 类似资料:
  • 问题内容: 我知道如何从-> “转换”一个简单的Java ,即: 现在,我想对地图进行基本相同的操作,即: 解决方案不应限于-> 。就像上面的示例一样,我想调用任何方法(或构造函数)。 问题答案: 它不如列表代码那么好。您不能在通话中构造new ,因此工作会混入通话中。

  • 我是Java 8流的新手。请提供建议,如何转换流<代码>流 例如,我在代码中有一些流: 我怎么能做这样的事 ? 对不起,我的英语不好。

  • 我尝试了这种方法,但得到了强制转换异常,不能将字符串转换为整数。

  • 我有和如下代码所示: 我尝试用< code>HashMap值替换该字符串,但这不起作用,因为< code>test是最终的,不能在< code>forEach的主体中重新分配。 那么有没有用Java 8 Stream API将< code>String替换为< code>HashMap的解决方案呢?

  • 问题内容: 是的实现,并且的构造函数接收类型参数。那么,为什么必须对其进行显式转换? 问题答案: 这是因为extends(又实现了)。您尝试将其输入。因此,它是不兼容的。 您需要将字符串属性一一输入到地图中。 例如:

  • 问题内容: 我有arrayList 我想像这样转换为ArrayList到HashMap 请帮助我如何转换为HashMap。 问题答案: 一般的方法是遍历,然后将值插入。示例如下: