【问题标题】:Java stream remove first three elementsJava 流删除前三个元素
【发布时间】:2018-12-18 16:06:44
【问题描述】:

我有按学生id排序的对象列表:

List<Student> arraylist = new ArrayList<>();
arraylist.add(new Student(1, "Chaitanya", 26));
arraylist.add(new Student(2, "Chaitanya", 26));
arraylist.add(new Student(3, "Rahul", 24));
arraylist.add(new Student(4, "Ajeet", 32));
arraylist.add(new Student(5, "Chaitanya", 26));
arraylist.add(new Student(6, "Chaitanya", 26));

我想使用 stream 并仅删除学生 age 等于 26 的前三个元素。 你能帮我解决这个问题吗?

【问题讨论】:

    标签: java arraylist java-stream


    【解决方案1】:

    您可以将filterskip 用作:

    List<Student> finalList = arraylist.stream()
            .filter(a -> a.getAge() == 26) // filters the students with age 26
            .skip(3) // skips the first 3 
            .collect(Collectors.toList());
    

    这将导致列出年龄等于 26 岁的 Students,同时跳过前三个出现的此类学生。


    另一方面,如果您只想从完整列表中排除这三个学生,您也可以这样做:

    List<Student> allStudentsExcludingFirstThreeOfAge26 = Stream.concat(
                arraylist.stream().filter(a -> a.getAge() != 26),
                arraylist.stream().filter(a -> a.getAge() == 26).skip(3))
            .collect(Collectors.toList());
    

    请注意,这可能会导致更改列表的原始顺序。

    【讨论】:

    • @Artifex 也更新了该用例的答案。
    • 很好的解决方案,但是请注意它会改变列表中元素的顺序。
    • @Andreas 嗯,有趣的是,正在考虑流行为本身。真实并更新为注释。除此之外,想知道我是否可以只使用Predicate.not 类型的实现而不像在我的代码中那样创建两次流。知道任何这样的结构吗?
    • 由于请求是关于“前三个”的,即有序测试,因此无论如何它都排除了支持并行流的实现,这意味着您可以违反规则并编写有状态过滤器。
    • @ernest_k 谢谢,我最初认为这个问题是我建议的解决方案。稍后更新。
    【解决方案2】:

    首先通过流 API 搜索您希望删除的元素:

    List<Student> toRemove = arraylist.stream()
                                      .filter(x -> x.getAge() == 26)
                                      .limit(3)
                                      .collect(toList());
    

    然后从源列表中删除:

    toRemove.forEach(arraylist::remove);
    

    如果您不想改变源代码,请先克隆它:

    List<Student> resultSet = new ArrayList<>(arraylist);
    List<Student> toRemove = arraylist.stream().filter(x -> x.getAge() == 26).limit(3)
                                      .collect(toList());
    toRemove.forEach(resultSet::remove);
    

    毕竟,使用迭代器可能会更好地实现:

    int counter = 0;
    for (Iterator<Student> it = arraylist.iterator(); it.hasNext();){        
          if(counter == 3) break;
          Student student = it.next();
          if (student.getAge() == 26){
              it.remove();
              counter++;
          }
    }
    

    【讨论】:

    • 虽然remove() 只删除第一个匹配项,但removeAll() 将删除所有 个匹配项。 removeAll() 不等于为传入集合的每个元素调用 remove()
    • @Andreas 对,我明白了,我相信迭代器方法可以解决。
    • 当然,迭代器方法不使用问题所要求的流。
    • @Andreas 当然,事情,有时最好的方法不是通过流。
    • 完全同意。 Streams 是一个非常方便的工具,但并非适用于所有工作。一个好的程序员会知道哪种工具最适合工作,而不是坚持使用锤子砍木头,而不是使用斧头。
    猜你喜欢
    • 2012-02-20
    • 2022-06-12
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    • 2012-07-10
    相关资源
    最近更新 更多