【问题标题】:Java 8 - Replace each row with GroupBy sumJava 8 - 用 GroupBy sum 替换每一行
【发布时间】:2022-02-02 22:19:14
【问题描述】:

我有数据类,它有 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 

【问题讨论】:

  • 一个流不能既按某个字段分组,又不能同时输出所有未分组的值。因此,这必须是一个两步过程:首先像您一样在地图中按年份聚合(使用第一个代码很好),然后使用该地图将聚合值重新附加到原始列表 - 即处理列表第二次并用地图中的值丰富它。由于这看起来像是一个学校练习,我认为你最好自己尝试一下,然后用你的尝试编辑你的问题。
  • 旁注,这看起来与两天前 this question 的练习相同——尽管格式要好得多,老实说——而且至少代码可以编译 :)
  • @DidierL 谢谢你的回复,这听起来像是一个学校练习,但有时即使经过很多努力也没有得到结果,那么最好在这里问。仅供参考,我刚刚开始使用 stacloverflow。
  • @AlexanderIvanchenko 我正在尝试执行此操作,但弹出如下消息:感谢您的反馈!您需要至少 15 声望才能投票,但您的反馈已被记录。
  • @AlexanderIvanchenko this question 如果 ID 结束 Year 是二等舱,并且我希望在两个列表的内部连接后输出相同的输出,那么该怎么做呢?

标签: java java-8 java-stream


【解决方案1】:

每年由您的代码 preserves only a single entry 中的第二个流创建的地图。

重映射函数(a, b) -&gt; new Data(a.getId(), a.getYear(), a.getName(), a.getValue() + b.getValue())) 负责处理重复项,以便每个数据对象的值将是所有值的总和。

为了给定年份的retain all Datachange 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
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-22
    • 2016-12-23
    • 1970-01-01
    • 1970-01-01
    • 2018-04-27
    • 2021-01-01
    • 2019-02-02
    相关资源
    最近更新 更多