Java 8流-或条件

10

看这段代码: (这段代码可以正常运行但是我不想使用2行,所以想知道如何改进)

ItemDetails[] items = response.getDetailsList();
items = Arrays.stream(items).filter(x -> !x.getName().equalsIgnoreCase("acl1")).toArray(ItemDetails[]::new);
items = Arrays.stream(items).filter(x -> !x.getName().equalsIgnoreCase("acl2")).toArray(ItemDetails[]::new);

我不知道如何在filter中使用OR(|)条件来删除List中的两个特定元素,因为这会导致编译时错误(在IDE中),所以我最终使用了上面的两个filters

我可能漏掉了什么?

items = Arrays.stream(items).filter(x -> !x.getName().equalsIgnoreCase("acl1") ||
        x -> !x.getName().equalsIgnoreCase("acl2")).toArray(ItemDetails[]::new);

=> IntelliJ 会对此(上面)抱怨。

items = Arrays.stream(items).filter(x -> !x.getName().equalsIgnoreCase("acl1"") ||
        x.getName().equalsIgnoreCase("acl2")).toArray(ItemDetails[]::new);

在运行时不起作用(它不进行过滤)

包含注释代码的完整代码(我尝试过的)供参考

public static void mapTest () {

        AclDetailItem[] items = new AclDetailItem[3];

        AclDetailItem item1 = new AclDetailItem();
        item1.setAclName("acl1");

        AclDetailItem item2 = new AclDetailItem();
        item2.setAclName("acl2");

        AclDetailItem item3 = new AclDetailItem();
        item3.setAclName("acl3");

        items[0] = item1;
        items[1] = item2;
        items[2] = item3;

        System.out.println ("Before " + items.length);


        items = Arrays.stream(items).filter(x -> !x.getAclName().equalsIgnoreCase("acl1")).toArray(ItemDetails[]::new);
        items = Arrays.stream(items).filter(x -> !x.getAclName().equalsIgnoreCase("acl2")).toArray(ItemDetails[]::new);

        System.out.println ("After "  + items.length);
    }

我没有点踩,但这是一个很差的问题。 - Carcigenicate
条件或是 ||,可能这是你的问题? - scrappedcola
1
@Rockoder 请将其编辑到原始问题中。 - Carcigenicate
4
移除你的第二个 x->... - Tunaki
这是一个理解失败的例子,后续应用过滤器等同于AND组合而不是OR,但成功地将每个读者引向错误方向,明确要求OR组合。如果您只想要一个单一的Stream操作,甚至不需要组合过滤器:ItemDetails[] items = Arrays.stream(response.getDetailsList()) .filter(x -> !x.getName().equalsIgnoreCase("acl1")) .filter(x -> !x.getName().equalsIgnoreCase("acl2")) .toArray(ItemDetails[]::new); - Holger
显示剩余4条评论
5个回答

25

你应该为每个条件创建多个谓词并使用or连接它们。我在下面添加了一个示例:

public class MeTest {

    Predicate<Integer> con1 = i -> i==0;
    Predicate<Integer> con2 = i -> i==1;
    Predicate<Integer> con3 = i -> i==2;

    @Test
    public void testOr() {
        List<Integer> asdas = IntStream.range(1, 10).boxed().filter(con1.or(con2).or(con3)).collect(toList());
        System.out.println("asdas = " + asdas);
    }
}

2
这通常是我首选的方法。它还允许实用类包含匹配谓词,这非常好。 - el n00b

6
第一个是不正确的,因为它有一个多余的x ->。 第二个不过滤,因为你构造了一个始终为true的条件。只需在filter方法中完善您的条件即可进行筛选。
编辑(由于问题变得详细): 我仍然认为您的条件存在错误。您可能想要排除acl1acl2两个条件。如果是这样,您的条件应该是这样的:
!(x.getAclName().equalsIgnoreCase("acl1") || x.getAclName().equalsIgnoreCase("acl2"))
// or if you prefer &&
!x.getAclName().equalsIgnoreCase("acl1") && !x.getAclName().equalsIgnoreCase("acl2")
// or if you prefer regular expressions/matches
!x.getAclName().matches("(?i)^acl[1|2]$")

谢谢!这个完美地运作。如果这可以帮助其他人,有人可以给我的问题点个赞吗?不确定为什么它是-1,当它吸引了来自人们的有效评论。 - Rockoder

1
items = Arrays.stream(items).filter(
    x -> !x.getName().equalsIgnoreCase("redirect")
    || x->!x.getName().equalsIgnoreCase("success"))
    .toArray(ItemDetails[]::new);

请注意第二个x->。它用于在lambda的开头绑定变量。将其放在中间是无效的,并且不必要,因为x已经存在于作用域中。只需删除这一部分即可。
items = Arrays.stream(items).filter(x ->
    !x.getName().equalsIgnoreCase("redirect")
    || !x.getName().equalsIgnoreCase("success"))
    .toArray(ItemDetails[]::new);

将测试此答案并更新。我认为我已经尝试了所有可能的排列组合,但并没有奏效。我尝试了许多变化,最终放弃了使用我发布的解决方案,因为我想继续下一个任务。 - Rockoder
更新:我的错,我在语法上搞砸了。现在它编译得很好。正在测试它。 - Rockoder
如果这个问题有效,请点赞哦!它会影响我的徽章/排名。 - Rockoder
@Rockoder,鉴于我没有样本数据可用,因此很难判断您条件的有效性。我也没有一个Java IDE方便使用,所以无法进行实际测试。您的主要问题是lambda中的双重变量绑定。您的条件是否真正实现了您想要的功能可以说是一个单独的问题。愚蠢的问题,但您知道filter会删除条件为false的元素,对吧?它“选择”true元素。 - Carcigenicate
你想要检查什么?是 aclGuestRedirect 还是 "redirect" - Carcigenicate
显示剩余2条评论

0

我有一个类似的问题:如何使用Java流来过滤满足CONDITION_1或CONDITION_2的对象子集。我想出了将两个条件都包含在过滤器中的方法。

myListOfElms().stream()
  .filter(elm -> elm.condition1OK() || elm.condition2OK())
  .collect(toList());

当然,将这些条件封装在一个私有方法中会使它看起来更好。但这就是想法。

0
   Question is "filter out with certain condition from Male or Female with one line"
    with consumer implementation for printing
    Answer
    --------
    public class Emp{
         private String name;
         private int age;
         private String gender; with setter, getter Allargument constructor}
    
    public class MailFemaleFilter {
        public static void main(String[] args) {
            List<Emp> empli=new ArrayList<Emp>();
            empli.add(new Emp("A",33,"m"));
            empli.add(new Emp("B",26,"m"));
            empli.add(new Emp("C",18,"m"));
            empli.add(new Emp("D",90,"m"));
            empli.add(new Emp("E",45,"m"));
            
            //female
            empli.add(new Emp("A1",7,"f"));
            empli.add(new Emp("B1",29,"f"));
            empli.add(new Emp("C1",70,"f"));
            empli.add(new Emp("D1",23,"f"));
            empli.add(new Emp("E1",39,"f"));
    //creation of predicate
    Predicate<Emp> agetest =  e-> e.getAge() > 30;
            Predicate<Emp> genderMtest =  m-> m.getGender().equals("m");
            Predicate<Emp> genderFtest =  mf-> mf.getGender().equals("f");
        List<Emp> FilteredEmp=empli.stream().filter(agetest.and((genderMtest).or(genderFtest)))
    .collect(Collectors.toList());  
    
    //printing by consumer
    
     MyConsumer action = new MyConsumer();
            FilteredEmp.forEach(action);
                    
            
        }
    
    }
    //creation of consumer implementation 
    class MyConsumer implements Consumer<Emp>{
    
        public void accept(Emp t) {
            System.out.println("Consumer impl name of emp ::"+t.getName()+":: with respective gender ::"
                    +t.getGender());
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接