Java流过滤器值的总和

V. *_*tis 9 java java-8 java-stream

我有一个叫做的类MonitoredData,它描述了一个活动,它的开始时间和结束时间.属性是activityLabel,startTime,endTime.我必须使用流分组和过滤这些活动,这些活动的总持续时间超过10小时.我设法计算持续时间的总和,并根据活动将它们分组:

Map<String, Long> map4 = new HashMap<String, Long>();

map4 = data.stream()
    .collect(
        Collectors.groupingBy(
            MonitoredData::getActivity, 
            Collectors.summingLong(MonitoredData::getDuration)
        )
    ); //getDuration returns end Time - startTime in milliseconds
Run Code Online (Sandbox Code Playgroud)

但我还没有设法添加过滤器.我试过用:

.filter(Collectors.summingLong(MonitoredData::getDuration) > whatever)
Run Code Online (Sandbox Code Playgroud)

但显然它不起作用.我怎样解决这个问题才能让它返回Map<String, Long>

Fed*_*ner 6

我会先做你已经做过的事情:我会将MonitoredData实例流收集到地图中,按活动分组并总结每个值中每个活动的持续时间:

Map<String, Long> map4 = data.stream()
    .collect(Collectors.groupingBy(
        MonitoredData::getActivity, 
        HashMap::new,
        Collectors.summingLong(MonitoredData::getDuration)));
Run Code Online (Sandbox Code Playgroud)

细微差别在于我正在使用接受工厂重载版本Collectors.groupingBy,因为在下一步中我想删除持续时间少于10小时的条目,并且规范不保证地图返回通过Collectors.groupingBy采用一个或两个参数的方法是可变的.

这是我删除不匹配的条目的方法:

public static final long TEN_HOURS_MS = 10 * 60 * 60 * 1000;

map4.values().removeIf(v -> v < TEN_HOURS_MS);
Run Code Online (Sandbox Code Playgroud)

如果您想在一行中执行所有操作,则可能需要使用Collectors.collectingAndThen:

Map<String, Long> map4 = data.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.groupingBy(
            MonitoredData::getActivity, 
            HashMap::new,
            Collectors.summingLong(MonitoredData::getDuration)),
        m -> { m.values().removeIf(v -> v < TEN_HOURS_MS); return m; } ));
Run Code Online (Sandbox Code Playgroud)

在这里,我习惯Collectors.collectingAndThen修改返回的地图Collectors.groupingBy.并且,在finisher函数中,我使用了它Collection.removeIf,它接受一个谓词并删除与该谓词匹配的所有条目.

  • 做得好.基本上,我昨晚想起了"removeOf",但我不确定,我正在打电话,我无法测试.并且您可以更清楚地描述从地图中删除小于10的持续时间. (2认同)

Sha*_*dov 3

我认为这就是你想要的,使用 Google Guava Maps 类:

Map<String, Long> map = Maps.filterValues(data.stream()
            .collect(Collectors.groupingBy
                    (MonitoredData::getActivity, Collectors.summingLong
                            (MonitoredData::getDuration)
                    )), value -> value > 3);
Run Code Online (Sandbox Code Playgroud)

显然,您可以编写自己的方法来过滤映射,但由于它已经存在,在如此流行的库上...如何使用纯流来做到这一点:我不知道,但也许这会令人满意。