Dictionary 使用Java8流API的HashMap的平均计数?

Dictionary 使用Java8流API的HashMap的平均计数?,dictionary,java-8,java-stream,Dictionary,Java 8,Java Stream,我有一张以下类型的地图 public class MapUtils { private Map<String, Integer> queryCounts = new HashMap<>(); public void averageCounters(){ int totalCounts = queryCounts.values().stream().reduce(0, Integer::sum); queryCounts = queryCoun

我有一张以下类型的
地图

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.replaceAll
而不是流API:

int totalCounts = queryCounts.values().stream()
                             .collect(Collectors.summingInt(Integer::intValue));
queryCounts.replaceAll((k, v) -> v/totalCounts);
然而,在您的情况下,这个解决方案是有问题的,因为除法结果将被四舍五入到一个
int
数字,因此您几乎总是在结果中得到零。实际上,代码中也存在同样的问题。您可能希望将
Map
作为结果类型。因此,您可能需要创建一个全新的
地图

Map<String, Double> averages = queryCounts.entrySet().stream()
                                          .collect(Collectors.toMap(Entry::getKey,
                                              e -> ((double)e.getValue())/totalCounts));
最后,还有一个选择,它是最有效的,但肮脏。在调用
averageCounters()
之后,您的代码假定原始(非平均)
queryCounts
是不必要的。因此,您可以将
queryCounts
保留为
Map
(这比向
Map
计数更有效),但随后更改
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;
double totalCounts=queryCounts.values().stream()
.collect(collector.summingit(Integer::intValue));
Map Map=(Map)查询计数;
map.replaceAll((k,v)->((整数)v)/totalCounts;
Map平均值=(Map)Map;
queryCounts=null;

类似的技巧也存在于
收集器.groupingBy
实现中的JDK中。

如果您想要就地修改,最好使用
映射。replaceAll
而不是流API:

int totalCounts = queryCounts.values().stream()
                             .collect(Collectors.summingInt(Integer::intValue));
queryCounts.replaceAll((k, v) -> v/totalCounts);
然而,在您的情况下,这个解决方案是有问题的,因为除法结果将被四舍五入到一个
int
数字,因此您几乎总是在结果中得到零。实际上,代码中也存在同样的问题。您可能希望将
Map
作为结果类型。因此,您可能需要创建一个全新的
地图

Map<String, Double> averages = queryCounts.entrySet().stream()
                                          .collect(Collectors.toMap(Entry::getKey,
                                              e -> ((double)e.getValue())/totalCounts));
最后,还有一个选择,它是最有效的,但肮脏。在调用
averageCounters()
之后,您的代码假定原始(非平均)
queryCounts
是不必要的。因此,您可以将
queryCounts
保留为
Map
(这比向
Map
计数更有效),但随后更改
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;
double totalCounts=queryCounts.values().stream()
.collect(collector.summingit(Integer::intValue));
Map Map=(Map)查询计数;
map.replaceAll((k,v)->((整数)v)/totalCounts;
Map平均值=(Map)Map;
queryCounts=null;
类似的技巧也存在于JDK中的
收集器.groupingBy
实现中