【问题标题】:Average counts from HashMap using java 8 stream API?使用 java 8 流 API 的 HashMap 的平均计数?
【发布时间】:2015-09-14 18:57:46
【问题描述】:

我有以下类型的Map

public class MapUtils {

    private Map<String, Integer> queryCounts = new HashMap<>();

public void averageCounters(){

    int totalCounts = queryCounts.values().stream().reduce(0, Integer::sum);
    queryCounts = queryCounts.entrySet()
                             .stream()
                             .collect(Collectors.toMap(
                                 Map.Entry::getKey,
                                 (Map.Entry::getValue)/totalCounts
    ));
}

这不会编译并在此行 (Map.Entry::getValue)/totalCounts 中显示错误。我该如何解决?有没有更好的方法来使用 Java 8 API 获得超过 Map 的平均值?

编辑: 这是更好的方法吗?

queryCounts.entrySet()
           .forEach(entry -> queryCounts.put(entry.getKey(),
                                   entry.getValue()/totalCounts));

【问题讨论】:

    标签: dictionary java-8 java-stream


    【解决方案1】:

    如果你想就地修改,最好使用Map.replaceAll而不是Stream API:

    int totalCounts = queryCounts.values().stream()
                                 .collect(Collectors.summingInt(Integer::intValue));
    queryCounts.replaceAll((k, v) -> v/totalCounts);
    

    但是,在您的情况下,此解决方案存在问题,因为除法结果将四舍五入为 int 数字,因此您几乎总是会在结果中得到零。实际上,您的代码中存在相同的问题。您可能希望将Map&lt;String, Double&gt; 作为结果类型。所以你可能需要创建一个全新的Map

    Map<String, Double> averages = queryCounts.entrySet().stream()
                                              .collect(Collectors.toMap(Entry::getKey,
                                                  e -> ((double)e.getValue())/totalCounts));
    

    另一种方法是首先将queryCounts 声明为Map&lt;String, Double&gt;。这样你就可以使用replaceAll:

    double totalCounts = queryCounts.values().stream()
                                 .collect(Collectors.summingDouble(Double::doubleValue));
    queryCounts.replaceAll((k, v) -> v/totalCounts);
    

    最后还有另一种最有效但又脏的替代方法。您的代码假定调用 averageCounters() 后不需要原始(非平均)queryCounts。因此,您可以将queryCounts 保留为Map&lt;String, Integer&gt;(这比计数到Map&lt;String, Double&gt; 更有效),然后像这样更改Map 值类型:

    double totalCounts = queryCounts.values().stream()
                                 .collect(Collectors.summingInt(Integer::intValue));
    Map<String, Object> map = (Map<String, Object>)queryCounts;
    map.replaceAll((k, v) -> ((Integer)v)/totalCounts);
    Map<String, Double> averages = (Map<String, Double>)map;
    queryCounts = null;
    

    类似的技巧是 JDK 中的 performed Collectors.groupingBy 实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-31
      相关资源
      最近更新 更多