我有一个格式的映射
Map<String, List<TableDTO>>
public class TableDTO {
private String countryName;
private String sourceName;
private int year;
private Double usageValue;
private Double powerUsers;
//Setter & Getters
}
我想找到usageValues和powerUsers的平均值,并且仍然保持TableDTO结构,usageValue可以为null,如果它为null,则完全忽略该对象。
<Chrome, <UK, Lorem, 2013, 2.90, 5.4>>
<Chrome, <US, Lorem, 2013, 4.10, 1.5>>
<Chrome, <EU, Lorem, 2013, 1.20, 0.22>>
<Chrome, <Asia, Lorem, 2013, 3.90, -1.10>>
<IE, <UK, Lorem, 2013, 1.40, 24.4>>
<IE, <US, Lorem, 2013, 0.90, 14.4>>
<IE, <EU, Lorem, 2013, 2.10, 0>>
<IE, <Asia, Lorem, 2013, 0.90, 0.4>>
<FF, <UK, Lorem, 2013, 0.10, 2.14>>
<FF, <US, Lorem, 2013, 1.10, 4.0>>
<FF, <EU, Lorem, 2013, , 4.4>>
<FF, <Asia, Lorem, 2013, 2.90, 4.4>>
预期结果
<1, <UK, Lorem, 2013, 1.47, 10.65>>
<2, <US, Lorem, 2013, 2.03, 6.63>>
<3, <Asia, Lorem, 2013, 2.57, 1.23>>
目前,在结果中,我已经用索引替换了键,这对现在来说很好。您会注意到,由于欧盟的FF值为空,因此整个欧盟都被忽略了,但对于其余部分,我计算了平均值。
如何在Java8中使用Lambda表达式来实现这一点,或者我必须进行迭代?
更新1:这是我目前所能做到的:
1.
Map<String, List<TableDTO>> dump = mapOfAllData.values()
.stream()
.flatMap(list -> list.stream())
.collect(Collectors.groupingBy(TableDTO::getCountryName));
Which give me a map with country names and the DTO orderd
2.
dump.values().stream().flatMap(list -> list.stream())
.filter((o -> !o.getUsageValue().isEmpty()))
.collect(Collectors.mapping(TableDTO::getUsageValue, Collectors.averagingDouble(Double::parseDouble)));
基本上得到平均值,但没有删除usageValue为空的DTO,我目前正在尝试解决这个问题。
更新2:
我设法把不需要的国家从地图上删除了。
我正在试图找出如何找到两个元素的平均值,我有这个表达式
newMap.values().stream().flatMap(list -> list.stream())
.collect(Collectors.mapping(TableDTO::usageValue, Collectors.averagingDouble(s -> s.isEmpty() ? Double.NaN : Double.parseDouble(s))));
// Collectors.mapping(TableDTO::powerUsers, Collectors.averagingDouble(c -> c.isEmpty() ? Double.NaN : Double.parseDouble(c))));
但我无法获得powerUsers的平均值。
要理解的是,您想要一个具有groupBy
countryName
、sourceName
、year
的每个List<TableDTO>
的平均值,但平均值在不同的字段上?
我希望usagePower
和powerUsers
是Double
,而不是像您的代码和使用Double.parseDouble
所建议的那样使用String。
这个代码应该做到:
package stackoverflow;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
public class TableDTO {
private final String countryName;
private final String sourceName;
private final int year;
@Nullable
private final Double usageValue;
private final Double powerUsers;
public TableDTO(final String countryName, final String sourceName, final int year, final Double usageValue,
final Double powerUsers) {
this.countryName = countryName;
this.sourceName = sourceName;
this.year = year;
this.usageValue = usageValue;
this.powerUsers = powerUsers;
}
public String getCountryName() {return countryName;}
public String getSourceName() {return sourceName;}
public int getYear() {return year;}
@Nullable public Double getUsageValue() {return usageValue;}
public Double getPowerUsers() {return powerUsers;}
@Override
public String toString() {
return "TableDTO [countryName=" + countryName + ", sourceName=" + sourceName + ", year=" + year + ", usageValue="
+ usageValue + ", powerUsers=" + powerUsers + "]";
}
public static void main(final String[] args) {
final java.util.Map<String, java.util.List<TableDTO>> data = new LinkedHashMap<>();
final List<TableDTO> chrome = new ArrayList<>();
chrome.add(new TableDTO("UK", "Lorem", 2013, 2.90, 5.4));
chrome.add(new TableDTO("US", "Lorem", 2013, 4.10, 1.5));
chrome.add(new TableDTO("EU", "Lorem", 2013, 1.20, 0.22));
chrome.add(new TableDTO("Asia", "Lorem", 2013, 3.90, -1.10));
data.put("Chrome", chrome);
final List<TableDTO> ie = new ArrayList<>();
ie.add(new TableDTO("UK", "Lorem", 2013, 1.40, 24.4));
ie.add(new TableDTO("US", "Lorem", 2013, 0.90, 14.4));
ie.add(new TableDTO("EU", "Lorem", 2013, 2.10, 0.));
ie.add(new TableDTO("Asia", "Lorem", 2013, 0.90, 0.4));
data.put("IE", ie);
final List<TableDTO> fx = new ArrayList<>();
fx.add(new TableDTO("UK", "Lorem", 2013, 0.10, 2.14));
fx.add(new TableDTO("US", "Lorem", 2013, 1.10, 4.0));
fx.add(new TableDTO("EU", "Lorem", 2013, null, 4.4));
fx.add(new TableDTO("Asia", "Lorem", 2013, 2.90, 4.4));
data.put("FX", fx);
data.values()
.stream()
.flatMap(List::stream)
.collect(Collectors.groupingBy(dto -> Arrays.asList(dto.getCountryName(), dto.getSourceName(), dto.getYear())))
.values()
.stream()
.filter(list -> list.stream().map(TableDTO::getUsageValue).noneMatch(Objects::isNull))
.map(
values -> {
final TableDTO root = values.iterator().next();
final double usageValueAvg = values.stream().map(TableDTO::getUsageValue).filter(Objects::nonNull)
.collect(Collectors.averagingDouble(Double::doubleValue));
final double powerUsersAvg = values.stream().map(TableDTO::getPowerUsers)
.collect(Collectors.averagingDouble(Double::doubleValue));
return new TableDTO(root.getCountryName(), root.getSourceName(), root.getYear(), usageValueAvg,
powerUsersAvg);
}).forEach(System.out::println);
;
}
}
结果是:
TableDTO [countryName=UK, sourceName=Lorem, year=2013, usageValue=1.4666666666666666, powerUsers=10.646666666666667]
TableDTO [countryName=US, sourceName=Lorem, year=2013, usageValue=2.033333333333333, powerUsers=6.633333333333333]
TableDTO [countryName=Asia, sourceName=Lorem, year=2013, usageValue=2.5666666666666664, powerUsers=1.2333333333333334]
解释:我已经用了你的一些代码来做了。
对
data
:的值执行flatMap
data.values() .stream() .flatMap(List::stream)
用一些密钥对
TableDTO
进行分组:我们不在乎密钥,唯一重要的是它正确地实现了hashCode
和equals
。Arrays.asList
起作用。否则,创建一个接受数组并使用Arrays.hashCode
/equals
的类Tuple。.collect(Collectors.groupingBy(dto -> Arrays.asList(dto.getCountryName(), dto.getSourceName(), dto.getYear()))) .values() .stream()
由于我们不想要列表,所以我们选择值并使用流。
我们过滤包含空
usageValue
:的TableDTO
.filter(list -> list.stream().map(TableDTO::getUsageValue).noneMatch(Objects::isNull))
然后我们做了一个映射,在这个映射中,您无法找到解决方案:由于组的原因,所有
TableDTO
共享相同的countryName
、sourceName
和year
值。而不是CCD_ 24和CCD_。因为列表不能为空,所以我们得到第一个元素。
.map( values -> { final TableDTO root = values.iterator().next();
在另一个结果上,我们计算过滤
usageValue
的任何空值的两个平均值。final double usageValueAvg = values.stream().map(TableDTO::getUsageValue).filter(Objects::nonNull) .collect(Collectors.averagingDouble(Double::doubleValue)); final double powerUsersAvg = values.stream().map(TableDTO::getPowerUsers) .collect(Collectors.averagingDouble(Double::doubleValue));
然后,我们基于三个分组密钥和两个平均值返回一个新的
TableDTO
。return new TableDTO(root.getCountryName(), root.getSourceName(), root.getYear(), usageValueAvg, powerUsersAvg); })
我们把它打印出来,瞧!:)
.forEach(System.out::println);
我希望它能解决你的问题。
我在Eclipse中测试了它,它进行了编译,但使用javac可能会失败,因为编译器与Lambdas的工作方式不同。