【问题标题】:How to use groupingBy with reducing without getting an Optional如何在不获取 Optional 的情况下使用 groupingBy 和减少
【发布时间】:2019-03-08 19:55:05
【问题描述】:

对于我的问题的这个大大简化的示例,我有一个 Stat 对象,其中包含一个 year 字段和其他三个统计字段。想象一下,结果是来自兽医链分支的每种动物类型的患者数量的年度统计数据,我想按年份获得所有分支的总和。

换句话说,从Stat 对象的列表中,我想返回一个Map<Integer, Stat>,其中整数是年份,而 Stat 对象具有年份和四个字段中每个字段的总和。

public class Stat
{
    int year;
    public int getYear() { return year; }

    long cats;
    public long getCats() { return cats; }

    long dogs;
    public long getDogs() { return dogs; }

    long pigeons;
    public long getPigeons() { return pigeons; }

    public Stat(int year, long cats, long dogs, long pigeons)
    {
        this.year = year;
        this.cats = cats;
        this.dogs = dogs;
        this.pigeons = pigeons;
    }

    public Stat(Stat left, Stat right)
    {
        if (left.year != right.year)
            throw new IllegalArgumentException("Only allow combining for same year.");
        this.year = left.year;
        this.cats = left.cats + right.cats;
        this.dogs = left.dogs + right.dogs ;
        this.pigeons = left.pigeons + right.pigeons;
    }

    @Override
    public String toString()
    {
        return String.format("%d c=%d d=%d p=%d", year, cats, dogs, pigeons);
    }
}
@Test
public void testStat()
{
    List<Stat> items = Arrays.asList(
        new Stat(2017, 5, 8, 12),
        new Stat(2017, 123, 382, 15),
        new Stat(2018, 1, 2, 3)
        );
    Map<Integer, Optional<Stat>> result = items.stream()
        .collect(Collectors.groupingBy(Stat::getYear,
            Collectors.reducing(Stat::new)
        ));
    System.out.println(result);
}

Optional 是不必要的,因为如果没有元素,groupingBy 永远不会创建需要 reducingList

有没有办法得到Map&lt;Integer, Stat&gt;,最好不用创建一个空白的“身份”对象?

如果我不得不求助于为reducing创建一个身份创建函数,Stat 对象的组合构造函数必须有一个年份(请参阅构造函数),那么身份构造函数如何获得传递给它的年份?

【问题讨论】:

  • 您会将四个字段的总和存储在哪里。
  • 它们存储在一个新实例中。请参阅构造函数 Stat(Stat left, Stat right)。它通过汇总各个字段来创建一个新的统计数据。但我应该说三个领域,因为只有狗、猫和鸽子。

标签: java java-8 java-stream grouping collectors


【解决方案1】:

您可以使用Collectors.toMap 来实现这一点:

Map<Integer, Stat> result = items.stream()
        .collect(Collectors.toMap(Stat::getYear, 
                Function.identity(), (one, another) -> sumStatsOfSameYear(one, another)));

sumAttributes 定义为

// stat from the same year
private static Stat sumStatsOfSameYear(Stat one, Stat another) {
    new Stat(one.getYear(), one.getCats() + another.getCats(),
            one.getDogs() + another.getDogs(), one.getPigeons() + another.getPigeons()))
}

【讨论】:

  • 谢谢!使用Collectors.toMap的方法完全正确!我试图让它变得比它必须的更难。请注意,在示例中,它可以只传递Stat::new,而不是传递函数调用sumStatsOfSameYear
猜你喜欢
  • 1970-01-01
  • 2020-04-10
  • 1970-01-01
  • 2017-09-10
  • 2021-02-23
  • 1970-01-01
  • 2016-02-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多