问题
I have an object of the following format
Map<String, List<ObjectDTO>> mapOfIndicators = new HashMap<>();
ObjectDTO is
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;
}
I am trying to compute the average of the newIndex value, which basically I cannot do as getNewIndex is String, and there can be empty string(values). I cannot convert to the null values to 0 as there will be 0 values in newIndex.
Is there an easier way to calculate the average?
Eg.
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);
Update 01: We can skip empty string/null values; the average would be per countryName, so I want to find the average of the newIndex for same contryName and eventually be able to get a Map as the final result.
回答1:
Not tested, but should do the trick (or at least guide you towards the solution):
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:
If you want to calculate the average of the values and collect them in a Map
having the same keys as the source map, you can do it this way:
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)));
Since ObjectDTO.newIndex
is declared private
, I assumed that there is a method getNewIndex
to get its value. I also provided the default value Double.NaN
as behavior for the case that there are no non-empty String
s in the value list which was not specified in the question.
In the case you want to average over a different key as with your question now defined more precisely, the code may look like:
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))));
Well, that’s similar to JB Nizet’s answer which got your intention right on the first guess…
来源:https://stackoverflow.com/questions/25851176/finding-average-using-lambda-double-stored-as-string