使用Lambda将列表分组并汇总到地图中

时间:2016-02-21 07:54:11

标签: java lambda java-8

我有一个MoveTrack个对象的列表,我想按月分组,并计算并将数据存储在Map<String, Double>中。我正在尝试学习Lambda并试验它,以便尝试用Lambda完成这项任务。

class MoveTrack {
private Date time;
private Double movementAmount;

//getters and setters
}

// in my main method
List<MoveTrack> mveTracking = new ArrayList<>();
Map<String, Double> movMap = new HashMap<>();

所以我希望能够对moveTracking列表进行分组并将值汇总到movMap,每个Map Key = Month Name(1月,2月等)和相应的Value运动金额是该月双打的总和。

3 个答案:

答案 0 :(得分:6)

如果您打开使用第三方库,Eclipse Collections会使用名为sumBy的专用方法,这些方法适用于lambdas。

如果您使用Eclipse Collections中的MutableList作为moveTracking列表,则代码如下所示:

MutableList<MoveTrack> moveTracking = Lists.mutable.empty();
ObjectDoubleMap<String> doubleMap =
    moveTracking.sumByDouble(MoveTrack::getMonthName, MoveTrack::getMovementAmount);

由您决定要在何处以及如何实施getMonthName()。您会注意到sumByDouble返回ObjectDoubleMap。这意味着您可以对double使用movementAmount,并且在求和期间不会将其装箱。

如果您想保留当前的List<MoveTrack>类型,可以使用ListAdapterIterate实用程序类来完成相同的操作。

List<MoveTrack> list = ...;
ObjectDoubleMap<String> doubleMap =
    Iterate.sumByDouble(list, MoveTrack::getMonthName, MoveTrack::getMovementAmount);

注意:我是Eclipse Collections的提交者

答案 1 :(得分:5)

Collectors.groupingBy允许您将列表缩减为映射,其中键是对列表元素的某些操作,值是一些应用于元素操作的聚合函数。 在你的情况下,你可以使用这样的东西:

SimpleDateFormat monthFormatter = new SimpleDateFormat("MMM");
Map<String, Double> moveMap = 
    moveTracking.stream()
                .collect(Collectors.groupingBy
                    (m -> monthFormatter.format(m.getTime()),
                     Collectors.summingDouble(MoveTrack::getMovementAmount)));

答案 2 :(得分:2)

使用Collectors.groupingBy,如下所示:

O(1)

代码适合您;)

mveTracking.stream().collect(Collectors.groupingBy(m -> {
            final Calendar cal = Calendar.getInstance();
            cal.setTime(m.getTime());
            final int month = cal.get(Calendar.MONTH);
            return new DateFormatSymbols().getMonths()[month];
        }, Collectors.summingDouble(MoveTrack::getMovementAmount)));