使用流从列表中获取总和和最大值

时间:2017-05-26 10:49:42

标签: java sum max grouping java-stream

嗨我有一个List,数据看起来像这样

[{"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;

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

所以最终结果看起来像

四月,周三,39 三月,星期二,62 5月,星期四,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方法错了,但我不知道如何编写它。

2 个答案:

答案 0 :(得分: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()));

答案 1 :(得分:0)

分两步完成,而不是尝试编写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);
});

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