简体   繁体   English

找出Java 8流过滤器是否已过滤某些内容的优雅方法

[英]Elegant way to find out if a Java 8 stream filter has filtered something

I have a List of Item fetched from a database. 我有一个从数据库中获取的Item List

I do something like: 我做的事情如下:

List<Item> list;
list.stream()
    .filter( i -> i.condition() )
    .mapToLong( Item::asLong )
    .sum()
    ;

Now I want to know, if the filter has filtered out something so I could delete this from my database where it is no longer needed. 现在我想知道,如果过滤器已经过滤掉了某些内容,那么我可以从我的数据库中删除它,不再需要它。

I could do: 我可以:

List<Item> list2 = list.stream()
    .filter( i -> i.condition() )
    .collect( Collectors.toList() )
    ;

int theSizeIWant = list2.size();

list2.stream().mapToLong( Item::asLong )
     .sum()
     ;

but I wonder if there is a more elegant solution which doesn't need to create the intermediate list. 但我想知道是否有一个更优雅的解决方案,不需要创建中间列表。

A possible solution would be to partition the Stream with the predicate and sum the values. 一种可能的解决方案是使用谓词对Stream进行分区并对值求和。 Partitioning is done with partitioningBy(predicate, downstream) . 使用partitioningBy(predicate, downstream)完成partitioningBy(predicate, downstream) In this case, the predicate would be your filtering function and the downstream collector would be summingLong to sum the values. 在这种情况下,谓词将是您的过滤函数,下游收集器将是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);
}

The map will contain the sum where the predicate is true (resp. false ) with the true key (resp. false ). 该地图将包含总和,其中谓词是true (相应地, false ),与true钥匙(分别为false )。

This way, if something has been filtered, sumWithTrueCondition will be strictly greater than 0. Furthermore, you can get the total sum by adding sumWithTrueCondition and sumWithFalseCondition . 这样,如果已经过滤了某些东西, sumWithTrueCondition将严格大于0.此外,您可以通过添加sumWithTrueConditionsumWithFalseCondition来获得总和。

Yes, you can do something like this. 是的,你可以做这样的事情。

Map<Boolean, List<Item>> partitions =
    list.stream.collect(Collectors.partitioningBy(i -> i.condition()));

Where partitions.get(true) will get you the good ones and partitions.get(false) will get you the ones to be deleted. 其中partitions.get(true)将为您提供好的,而partitions.get(false)将为您提供要删除的内容。

Another solution is to count the bad elements in the lambda expression: 另一个解决方案是计算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);

This alleviates the intermediate list, it still need a second calculation though. 这减轻了中间列表,但仍然需要进行第二次计算。 If something doesn't pass the condition, it wont pass further down the stream, and won't get counted. 如果某些事情没有通过这个条件,那么它就不会再向下流过,并且不会被计算在内。

int count = 0;

count has to be an instance variable, and then you can do this: count必须是一个实例变量,然后你可以这样做:

List<Item> list;
list.stream()
    .filter( i -> i.condition() )
    .mapToLong( (item) -> { count++; return item.asLong(); } )
    .sum();

boolean isFiltered = list.size() > count;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM