Java 8 - 用 GroupBy 总和替换每一行
Java 8 - Replace each row with GroupBy sum
我有 class 数据,它有 4 个字段并有值列表,然后我想用 java 8 和流替换每一行按年份分组并求和同一年份的值。请看下面的代码和输出。
class Data {
int id;
int year;
String name;
double value;
}
List<Data> list = new ArrayList<>();
list.add(new Data(101, 2018, "AAA", 20));
list.add(new Data(102, 2019, "BBB", 30));
list.add(new Data(103, 2020, "CCC", 10));
list.add(new Data(104, 2019, "DDD", 50));
list.add(new Data(105, 2020, "EEE", 40));
list.add(new Data(106, 2020, "FFF", 60));
第一个代码尝试:
list.stream().collect(Collectors.groupingBy(Data::getYear, Collectors
.summingDouble(Data::getValue)));
第二个代码尝试:
list.stream().collect(Collectors.toMap(value -> value.getYear(), Function.identity(),
(a, b) -> new Data(a.getId(), a.getYear(), a.getName(), a.getValue() + b.getValue()))).values()
.forEach(value -> System.out.println(value));
输出:
id year name value
101 2018 "AAA" 20
102 2019 "BBB" 80
103 2020 "CCC" 110
预期输出:
id year name value
101 2018 "AAA" 20
102 2019 "BBB" 80
103 2020 "CCC" 110
104 2019 "DDD" 80
105 2020 "EEE" 110
106 2020 "FFF" 110
地图由您的代码中的第二个流创建,每年 preserves only a single entry
。
重映射函数 (a, b) -> new Data(a.getId(), a.getYear(), a.getName(), a.getValue() + b.getValue()))
处理重复项,以便每个数据对象的值将是所有值的总和。
为了 retain all
给定年份的 Data
和 change the value of every object to be a total value
,您必须采取几个步骤:
- 创建地图:
year
--> total value per year
(已正确完成);
- 创建地图:
year
--> list of Data
个对象;
- 将
total value per year
应用于每个 Data
对象。
public static void main(String[] args) {
List<Data> dataList = List.of(
new Data(101, 2018, "AAA", 20),
new Data(102, 2019, "BBB", 30),
new Data(103, 2020, "CCC", 10),
new Data(104, 2019, "DDD", 50),
new Data(105, 2020, "EEE", 40),
new Data(106, 2020, "FFF", 60)
);
Map<Integer, Double> yearToTotalVal = getTotalValueMap(dataList);
Map<Integer, List<Data>> yearToData = getYearToDataListMap(dataList);
appllyTotalValue(yearToTotalVal, yearToData);
for (Map.Entry<Integer, List<Data>> entry: yearToData.entrySet()) {
System.out.println(entry);
}
}
private static Map<Integer, Double> getTotalValueMap(List<Data> dataList) {
return dataList.stream()
.collect(Collectors.groupingBy(Data::getYear,
Collectors.summingDouble(Data::getValue)));
}
private static Map<Integer, List<Data>> getYearToDataListMap(List<Data> dataList) {
return dataList.stream()
.collect(Collectors.groupingBy(Data::getYear));
}
private static void appllyTotalValue(Map<Integer, Double> yearToTotalVal,
Map<Integer, List<Data>> yearToData) {
for (Integer year: yearToTotalVal.keySet()) {
yearToData.get(year)
.replaceAll(data -> new Data(data.getId(),
data.getYear(),
data.getName(),
yearToTotalVal.get(year)));
}
}
输出 - 每年的数据:
2018=[Data{id=101, year=2018, name='AAA', value=20.0}]
2019=[Data{id=102, year=2019, name='BBB', value=80.0}, Data{id=104, year=2019, name='DDD', value=80.0}]
2020=[Data{id=103, year=2020, name='CCC', value=110.0}, Data{id=105, year=2020, name='EEE', value=110.0}, Data{id=106, year=2020, name='FFF', value=110.0}]
旁注:
- 我还建议你制作
Data class immutable
public class Data {
private final int id;
private final int year;
private final String name;
private final double value;
// Constructor, getters, etc
}
我有 class 数据,它有 4 个字段并有值列表,然后我想用 java 8 和流替换每一行按年份分组并求和同一年份的值。请看下面的代码和输出。
class Data {
int id;
int year;
String name;
double value;
}
List<Data> list = new ArrayList<>();
list.add(new Data(101, 2018, "AAA", 20));
list.add(new Data(102, 2019, "BBB", 30));
list.add(new Data(103, 2020, "CCC", 10));
list.add(new Data(104, 2019, "DDD", 50));
list.add(new Data(105, 2020, "EEE", 40));
list.add(new Data(106, 2020, "FFF", 60));
第一个代码尝试:
list.stream().collect(Collectors.groupingBy(Data::getYear, Collectors
.summingDouble(Data::getValue)));
第二个代码尝试:
list.stream().collect(Collectors.toMap(value -> value.getYear(), Function.identity(),
(a, b) -> new Data(a.getId(), a.getYear(), a.getName(), a.getValue() + b.getValue()))).values()
.forEach(value -> System.out.println(value));
输出:
id year name value
101 2018 "AAA" 20
102 2019 "BBB" 80
103 2020 "CCC" 110
预期输出:
id year name value
101 2018 "AAA" 20
102 2019 "BBB" 80
103 2020 "CCC" 110
104 2019 "DDD" 80
105 2020 "EEE" 110
106 2020 "FFF" 110
地图由您的代码中的第二个流创建,每年 preserves only a single entry
。
重映射函数 (a, b) -> new Data(a.getId(), a.getYear(), a.getName(), a.getValue() + b.getValue()))
处理重复项,以便每个数据对象的值将是所有值的总和。
为了 retain all
给定年份的 Data
和 change the value of every object to be a total value
,您必须采取几个步骤:
- 创建地图:
year
-->total value per year
(已正确完成); - 创建地图:
year
-->list of Data
个对象; - 将
total value per year
应用于每个Data
对象。
public static void main(String[] args) {
List<Data> dataList = List.of(
new Data(101, 2018, "AAA", 20),
new Data(102, 2019, "BBB", 30),
new Data(103, 2020, "CCC", 10),
new Data(104, 2019, "DDD", 50),
new Data(105, 2020, "EEE", 40),
new Data(106, 2020, "FFF", 60)
);
Map<Integer, Double> yearToTotalVal = getTotalValueMap(dataList);
Map<Integer, List<Data>> yearToData = getYearToDataListMap(dataList);
appllyTotalValue(yearToTotalVal, yearToData);
for (Map.Entry<Integer, List<Data>> entry: yearToData.entrySet()) {
System.out.println(entry);
}
}
private static Map<Integer, Double> getTotalValueMap(List<Data> dataList) {
return dataList.stream()
.collect(Collectors.groupingBy(Data::getYear,
Collectors.summingDouble(Data::getValue)));
}
private static Map<Integer, List<Data>> getYearToDataListMap(List<Data> dataList) {
return dataList.stream()
.collect(Collectors.groupingBy(Data::getYear));
}
private static void appllyTotalValue(Map<Integer, Double> yearToTotalVal,
Map<Integer, List<Data>> yearToData) {
for (Integer year: yearToTotalVal.keySet()) {
yearToData.get(year)
.replaceAll(data -> new Data(data.getId(),
data.getYear(),
data.getName(),
yearToTotalVal.get(year)));
}
}
输出 - 每年的数据:
2018=[Data{id=101, year=2018, name='AAA', value=20.0}]
2019=[Data{id=102, year=2019, name='BBB', value=80.0}, Data{id=104, year=2019, name='DDD', value=80.0}]
2020=[Data{id=103, year=2020, name='CCC', value=110.0}, Data{id=105, year=2020, name='EEE', value=110.0}, Data{id=106, year=2020, name='FFF', value=110.0}]
旁注:
- 我还建议你制作
Data class immutable
public class Data {
private final int id;
private final int year;
private final String name;
private final double value;
// Constructor, getters, etc
}