java 将包含值列表的Map转换为另一个包含列表中所有值的平均值的Map

gab6jxml  于 2023-02-28  发布在  Java
关注(0)|答案(2)|浏览(106)

我正在将一个包含键和相应值列表的Map转换为Map〈String,Double〉,其中的值是平均得分。有没有简洁的方法可以做到这一点?

Map<String, List<Float>> scoresMap = Map.of(
                "Prod1", List.of(2f, 2f, 2f, 2f),
                "Prod2", List.of(4f, 4f, 4f, 4f),
                "Prod3", List.of(6f, 6f, 6f, 6f),
                "Prod4", List.of(8f, 8f, 8f, 8f));

        Map<String, Double> averageScores = new HashMap<>();

        scoresMap.forEach( (key, value) -> {
            averageScores.put(key, value.stream().mapToDouble(d -> d).average().getAsDouble());
                }
        );
ffscu2ro

ffscu2ro1#

虽然将Map转换为流然后将条目收集回Map中当然是可能的,但我并不完全相信这种方法是最有意义的。

var map = scoresMap.entrySet().stream()
            .collect(Collectors.toMap(
                    Map.Entry::getKey,
                    e -> e.getValue().stream().collect(
                            Collectors.averagingDouble(Float::doubleValue)
                    )
            ));

也许如果在流中有进一步的处理要做,那么这样做是有意义的,但在我看来,它有混淆代码目的的风险。

uurity8g

uurity8g2#

是的,可以使用toMap收集器:

final Map<String, List<Float>> scoresMap = Map.of(
        "Prod1", List.of(2f, 2f, 2f, 2f),
        "Prod2", List.of(4f, 4f, 4f, 4f),
        "Prod3", List.of(6f, 6f, 6f, 6f),
        "Prod4", List.of(8f, 8f, 8f, 8f));

final Map<String, Double> averageScores = scoresMap.entrySet()
        .stream()
        .collect(Collectors.toMap(
                Map.Entry::getKey,
                entry -> entry.getValue()
                        .stream()
                        .mapToDouble(d -> d)
                        .average()
                        .getAsDouble()));

为了保持代码的可读性,我建议将求平均值的操作提取到一个单独的方法中:

final double average(final Collection<Float> floats) {
    return floats.stream()
            .mapToDouble(d -> d)
            .average()
            .getAsDouble();
}

final Map<String, Double> averageScores = scoresMap.entrySet()
        .stream()
        .collect(Collectors.toMap(
                Map.Entry::getKey,
                entry -> average(entry.getValue())));

或者甚至是:

final Function<Map.Entry<?, List<Float>>, Double> averaging
        = entry -> average(entry.getValue());
final Map<String, Double> averageScores = scoresMap.entrySet()
        .stream()
        .collect(Collectors.toMap(Map.Entry::getKey, averaging));

相关问题