【问题标题】:Getting the sum and max from a list using stream使用流从列表中获取总和和最大值
【发布时间】:2017-05-26 10:49:42
【问题描述】:

您好,我有一个列表,其中的数据如下所示

[{"month":"April","day":"Friday","count":5},

{"month":"April","day":"Monday","count":6},

{"month":"April","day":"Saturday","count":2},

{"month":"April","day":"Sunday","count":1},

{"month":"April","day":"Thursday","count":7},

{"month":"April","day":"Tuesday","count":8},

{"month":"April","day":"Wednesday","count":10},

{"month":"March","day":"Friday","count":3},

{"month":"March","day":"Monday","count":2},

{"month":"March","day":"Saturday","count":15},

{"month":"March","day":"Sunday","count":11},

{"month":"March","day":"Thursday","count":4},

{"month":"March","day":"Tuesday","count":20},

{"month":"March","day":"Wednesday","count":7},

{"month":"May","day":"Friday","count":2},

{"month":"May","day":"Monday","count":0},

{"month":"May","day":"Saturday","count":7},

{"month":"May","day":"Sunday","count":4},

{"month":"May","day":"Thursday","count":8},

{"month":"May","day":"Tuesday","count":3},

{"month":"May","day":"Wednesday","count":6}]

我的对象类是

String month;
String day;
Integer count;

我想通过使用流得到的是按月分组的计数总和以及该月最大计数的日期。

所以最终结果看起来像

4 月 39 日星期三 三月,星期二,62 五月,星期四,30

我一直在尝试使用流和分组,但没有运气。任何帮助表示赞赏。谢谢

编辑

 Map<String, Integer> totalMap = transactions.stream().collect(Collectors.groupingBy(MonthlyTransaction::getMonth, Collectors.summingInt(MonthlyTransaction::getCount)));
     Map<String, String> maxMap = transactions.stream().collect(Collectors.groupingBy(MonthlyTransaction::getMonth)).values().stream().toMap(Object::getDay, Collextions.max(Object::getCount);

显然maxMap方法是错误的,但我不知道怎么写。

【问题讨论】:

  • 你能展示一些你的尝试吗?
  • 我设法得到了总和,但我正在努力用当月的最大计数来映射这一天。下面是我现在拥有的代码。 transactions.stream().collect(Collectors.groupingBy(Object::getMonth, Collectors.summingInt(Object::getCount)));
  • 月份和日期在您的列表中是唯一的吗?如果我看一下预期的结果,四月的其他日子在哪里?我不明白这个商业案例。
  • 月份和日期是独一无二的。在预期的结果中,4 月共有 39 个计数,而周三的计数最多
  • 请将填充数据的代码发布到列表变量中...

标签: java sum max grouping java-stream


【解决方案1】:

如果您想一次性找到每月计数的总和和每月最大计数的日期,我认为您需要一个自定义收集器。

首先,让我们创建一个持有者类来存储结果:

public class Statistics {

    private final String dayWithMaxCount;

    private final long totalCount;

    public Statistics(String dayWithMaxCount, long totalCount) {
        this.dayWithMaxCount = dayWithMaxCount;
        this.totalCount = totalCount;
    }

    // TODO getters and toString
}

然后,创建此方法,该方法返回一个收集器,该收集器累积计数总和和最大计数,以及找到最大值的日期:

public static Collector<MonthlyTransaction, ?, Statistics> withStatistics() {
    class Acc {
        long sum = 0;
        long maxCount = Long.MIN_VALUE;
        String dayWithMaxCount;

        void accumulate(MonthlyTransaction transaction) {
            sum += transaction.getCount();
            if (transaction.getCount() > maxCount) {
                maxCount = transaction.getCount();
                dayWithMaxCount = transaction.getDay();
            }
        }

        Acc merge(Acc another) {
            sum += another.sum;
            if (another.maxCount > maxCount) {
                maxCount = another.maxCount;
                dayWithMaxCount = another.dayWithMaxCount;
            }
            return this;
        }

        Statistics finish() {
            return new Statistics(dayWithMaxCount, sum);
        }
    }
    return Collector.of(Acc::new, Acc::accumulate, Acc::merge, Acc::finish);
}

这使用本地类Acc 来累积和合并部分结果。 finish 方法返回 Statistics 类的实例,该类保存最终结果。最后,我使用Collector.of基于Acc类的方法创建了一个收集器。

最后,你可以使用上面定义的方法和类如下:

Map<String, Statistics> statisticsByMonth = transactions.stream()
    .collect(Collectors.groupingBy(MonthlyTransaction::getMonth, withStatistics()));

【讨论】:

  • 非常感谢。这太棒了。我没有想到我可以编写一个自定义收集器方法(新学到的东西)。这工作得很好!
【解决方案2】:

分两步完成,而不是尝试写入 1 个流来实现结果

//First get the total of counts grouping by month
Map<String, Integer> totalMap = transactions.stream()
  .collect(Collectors.groupingBy(MonthlyTransaction::getMonth, Collectors.summingInt(MonthlyTransaction::getCount)));

List<MonthlyTransaction> finalStat = new ArrayList<>();

//iterate over the total count map
totalMap.entrySet().stream().forEach(entry -> {
//Using the Stream filter to mimic a group by 
MonthlyTransaction maxStat = transactions.stream()
    .filter(t -> t.getMonth().equals(entry.getKey()))
        //getting the item with the max count for the month
       .max(Comparator.comparing(MonthlyTransaction::getCount)).get();

//Setting the count to the total value from the map as the max count value is not a requirement.
maxStat.setCount(entry.getValue());

//add the item to the list
finalStat.add(maxStat);
});

这可能不是解决问题的最佳方法,但这给了我确切的结果。感谢所有看过它并试图提供帮助的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-16
    • 1970-01-01
    • 2021-09-17
    • 2018-10-30
    • 1970-01-01
    • 2023-03-03
    • 2020-09-22
    • 1970-01-01
    相关资源
    最近更新 更多