【问题标题】:Finding average using Lambda (Double stored as String)使用 Lambda 求平均值(双重存储为字符串)
【发布时间】:2014-09-15 15:07:44
【问题描述】:

我有一个如下格式的对象

Map<String, List<ObjectDTO>> mapOfIndicators = new HashMap<>();

ObjectDTO 是

public class ObjectDTO {
 private static final long   serialVersionUID = 1L;

    private String iName;
    private String dName;
    private String countryName;
    private int year;

    //Since the value can be empty, using String instead of Double
    private String newIndex;
}

我正在尝试计算 newIndex 值的平均值,因为 getNewIndex 是字符串,所以基本上我无法做到这一点,并且可以有空字符串(值)。我无法将 null 值转换为 0,因为 newIndex 中将有 0 个值。

有没有更简单的方法来计算平均值?

例如。

mapOfIndicators = new HashMap<>();
List<IndicatorTableDTO> _tempValue = new ArrayList();
IndicatorTableDTO _iTDTO = new IndicatorTableDTO("iName", "dName", "countryName1", 2012, "1.00");
_tempValue.add(_iTDTO);
_iTDTO = new IndicatorTableDTO("iName", "dName", "countryName2", 2012, "");
_tempValue.add(_iTDTO);
_iTDTO = new IndicatorTableDTO("iName", "dName", "countryName3", 2012, "0.02");
_tempValue.add(_iTDTO);
_iTDTO = new IndicatorTableDTO("iName", "dName", "countryName4", 2012, "-0.25");
_tempValue.add(_iTDTO);
_iTDTO = new IndicatorTableDTO("iName", "dName", "countryName5", 2012, "0.10");
_tempValue.add(_iTDTO);

mapOfIndicators.put("Test1", _tempValue);

   _iTDTO = new IndicatorTableDTO("iName", "dName", "countryName1", 2012, "0.10");
   _tempValue.add(_iTDTO);
   _iTDTO = new IndicatorTableDTO("iName", "dName", "countryName2", 2012, "", "", "");
   _tempValue.add(_iTDTO);
   _iTDTO = new IndicatorTableDTO("iName", "dName", "countryName3", 2012, "", "", "");
   _tempValue.add(_iTDTO);
   _iTDTO = new IndicatorTableDTO("iName", "dName", "countryName4", 2012, "0.25", "", "");
   _tempValue.add(_iTDTO);
   _iTDTO = new IndicatorTableDTO("iName", "dName", "countryName5", 2012, "1.10", "", "");
   _tempValue.add(_iTDTO);

   mapOfIndicators.put("Test2", _tempValue);

更新 01:我们可以跳过空字符串/空值;平均值是每个 countryName,所以我想找到相同 contryName 的 newIndex 的平均值,并最终能够得到一个 Map 作为最终结果。

【问题讨论】:

  • 您应该包括您的传统计算方式,以使您的意图更加清晰。你想要每个地图条目的平均值还是整个地图的平均值,你想要将空字符串视为 0 还是跳过它们(这不一样……)?
  • 有一个简单的方法,只要你定义了平均值应该是多少。如果你不知道字符串为空时整数值应该是什么,我们也不知道。
  • @Holger,更新了底部的问题
  • @JB-Nizet 更新了问题
  • @Vivek:所以countryName 已经是地图的关键了?

标签: lambda average java-8


【解决方案1】:

未经测试,但应该可以解决问题(或至少引导您找到解决方案):

Map<String, Double> averageByCountryName = 
    map.values()
       .stream()
       .flatMap(list -> list.stream())
       .filter(objectDTO -> !objectDTO.getNewIndex().isEmpty())
       .collect(Collectors.groupingBy(
            ObjectDTO::getCountry,
            Collectors.averagingDouble(
                objectDTO -> Double.parseDouble(objectDTO.getNewIndex())));

【讨论】:

    【解决方案2】:

    如果您想计算这些值的平均值并将它们收集在与源映射具有相同键的Map 中,您可以这样做:

    Map<String, Double> averages=mapOfIndicators.entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getKey, e->e.getValue().stream()
           .map(ObjectDTO::getNewIndex).filter(str->!str.isEmpty())
           .mapToDouble(Double::parseDouble).average().orElse(Double.NaN)));
    

    由于ObjectDTO.newIndex 被声明为private,我假设有一个方法getNewIndex 来获取它的值。我还提供了默认值 Double.NaN 作为问题中未指定的值列表中没有非空 Strings 的情况的行为。


    如果您想对不同的键进行平均,因为您现在更精确地定义了您的问题,代码可能如下所示:

    Map<String, Double> averages=mapOfIndicators.values().stream()
        .flatMap(Collection::stream)
        .filter(objectDTO -> !objectDTO.getNewIndex().isEmpty())
        .collect(Collectors.groupingBy(ObjectDTO::getCountryName,
            Collectors.mapping(ObjectDTO::getNewIndex,
                Collectors.averagingDouble(Double::parseDouble))));
    

    嗯,这类似于JB Nizet’s answer,它在第一次猜测时就让你的意图正确......

    【讨论】:

    • 对不起,如果我之前的笔记让您感到困惑。 ObjectDTO 具有 countryName 而不是我们尝试从中读取的 Map,如果您看到上面的示例,则 Key 是“Test1”和“Test2”。我们需要创建一个新的可能,其中 ObjectDTO.getCountryName() 作为键和列表中所有国家/地区名称的平均值;来自 Test1 和 Test2。
    • 谢谢,您的解决方案看起来也很优雅。一个简单的问题,您在此处添加的过滤器正在检查它不是空的,如果其中一个是该国家/地区的 newIndex 是空的,有没有办法可以忽略整个国家/地区映射?
    • @Vivek:这不是一个“快速的问题”,而是一个全新的问题。提出新问题不是 cmets 的预期范围。
    • @Vivek:你可以创建一个新问题,你知道……
    猜你喜欢
    • 1970-01-01
    • 2015-12-26
    • 1970-01-01
    • 1970-01-01
    • 2019-06-19
    • 1970-01-01
    • 2011-11-09
    • 1970-01-01
    • 2012-12-27
    相关资源
    最近更新 更多