我从数据库中获取List
Item
。
我做的事情如下:
List<Item> list;
list.stream()
.filter( i -> i.condition() )
.mapToLong( Item::asLong )
.sum()
;
现在我想知道,如果过滤器已经过滤掉了某些内容,那么我可以从我的数据库中删除它,不再需要它。
我能做到:
List<Item> list2 = list.stream()
.filter( i -> i.condition() )
.collect( Collectors.toList() )
;
int theSizeIWant = list2.size();
list2.stream().mapToLong( Item::asLong )
.sum()
;
但我想知道是否有一个更优雅的解决方案,不需要创建中间列表。
答案 0 :(得分:4)
一种可能的解决方案是使用谓词对Stream进行分区并对值求和。使用partitioningBy(predicate, downstream)
进行分区。在这种情况下,谓词将是您的过滤函数,下游收集器将summingLong
来对值进行求和。
public static void main(String[] args) {
List<Item> list = new ArrayList<>();
Map<Boolean, Long> map =
list.stream()
.collect(Collectors.partitioningBy(
Item::condition,
Collectors.summingLong(Item::asLong)
));
long sumWithTrueCondition = map.get(true);
long sumWithFalseCondition = map.get(false);
}
地图将包含谓词true
(分别为false
)与true
键(分别为false
)的总和。
这样,如果某些内容已被过滤,sumWithTrueCondition
将严格大于0.此外,您可以通过添加sumWithTrueCondition
和sumWithFalseCondition
来获得总和。
答案 1 :(得分:3)
是的,你可以这样做。
Map<Boolean, List<Item>> partitions =
list.stream.collect(Collectors.partitioningBy(i -> i.condition()));
partitions.get(true)
会为您提供好的,partitions.get(false)
会为您提供要删除的内容。
答案 2 :(得分:0)
另一个解决方案是计算lambda表达式中的坏元素:
List<String> strings = Arrays.asList("1", "2", "3", "12", "4", "5");
List<String> badOnes = new ArrayList<>();
strings.stream()
.filter(s -> {
boolean returnValue = !s.contains("1");
if (!returnValue) {
badOnes.add(s);
}
return returnValue;
})
.forEach(s -> System.out.println(s));
System.out.println(badOnes);
答案 3 :(得分:0)
这减轻了中间列表,但仍然需要进行第二次计算。如果某些事情没有通过这个条件,那么它就不会再向下流过,并且不会被计算在内。
int count = 0;
count必须是一个实例变量,然后你可以这样做:
List<Item> list;
list.stream()
.filter( i -> i.condition() )
.mapToLong( (item) -> { count++; return item.asLong(); } )
.sum();
boolean isFiltered = list.size() > count;