【问题标题】:Intersection of Two Lists Objects in java 8java 8中两个列表对象的交集
【发布时间】:2018-12-16 17:58:19
【问题描述】:

java 8 中两个列表对象的交集。有人能告诉我我做错了什么吗?

List<Student> originalStudent = new ArrayList<>();
List<Student> newStudent = new ArrayList<>();

List<Student> intersectListStudent = new LinkedList<>()

originalStudent.add(new Student("William", "Tyndale",1));
originalStudent.add(new Student("Jonathan", "Edwards",2));
originalStudent.add(new Student("Martin", "Luther"),3);

newStudent.add(new Student("Jonathan", "Edwards",2));
newStudent.add(new Student("James", "Tyndale",4));
newStudent.add(new Student("Roger", "Moore",5));


originalStudent.forEach(n ->
        newStudent.stream()
                .filter(db -> !n.getName().equals(db.getName()) &&
                        !n.getLastName().equals(db.getLastName()))
                    .forEach(student-> intersectListStudent .add(student)));

【问题讨论】:

  • 您期望的输出是什么?你认为什么是错的?顺便说一句,这不是自我解释
  • 由于一个List可以多次包含同一个元素,所以当你交叉列表时,如果A有元素x三次,B有元素x两次,多少次你期待最终名单中的答案吗? 3? 2? 1?这将确定这些方法中的哪一种有效。

标签: java arraylist java-8 java-stream intersect


【解决方案1】:

谁能告诉我我做错了什么?

您违反了Side-effects 原则,简而言之,流不应该在通过管道执行操作时修改另一个集合。我没有测试你的代码,但是,这不是你应该处理流的方式。


如何做得更好?

只需在过滤器的谓词中使用List::contains 即可去除唯一值。

List<Student> students = originalStudent.stream()
                                        .filter(newStudent::contains)
                                        .collect(Collectors.toList());

此解决方案(了解List::contains 方法)基于使用Object::equals 实现的相等比较。因此,需要重写 Student 类中的相同方法。

编辑:请注意,自动覆盖Object::equals 将介意id 进行相等计算。因此,平等将仅基于姓名和姓氏。 (感谢@nullpointer)。

没有覆盖Object::equals

您必须使用另一个streamStream::anyMatch 方法在filter 中执行比较,如果谓词合格,则返回true

List<Student> students = originalStudent.stream()
              .filter(os -> newStudent.stream()                    // filter
                  .anyMatch(ns ->                                  // compare both
                       os.getName().equals(ns.getName() &&         // name
                       os.getLastName().equals(ns.getLastName()))) // last name
              .collect(Collectors.toList());

【讨论】:

  • 这肯定需要对象比较。此外,由于提供的两个示例列表中的最后一个属性值更改,因此此处的输出将与问题中的预期有所不同。
  • 我的意思是,如果我将 originalStudent.add(new Student("Jonathan", "Edwards",2)); 更改为 originalStudent.add(new Student("Jonathan", "Edwards",7));,您的第一个代码块将不会提供与您后一个建议相同的输出。
  • 加一个用于anyMatchcollect 的解决方案 :)
  • @Myjay1516,为什么这不是公认的答案? ://
【解决方案2】:

您可以从originalStudentnewStudent 两个串联列表中构造一个SortedSet&lt;Student&gt;。排序后的集合使用Comparator.comparing(Student::getName).thenComparing(Student::getLastName) 作为比较器。

Stream.concat(originalStudent.stream(), newStudent.stream())
    .collect(Collectors.toCollection(() -> new TreeSet<>(
        Comparator.comparing(Student::getFname)
            .thenComparing(Student::getLname))
    ))

【讨论】:

  • 对我来说很好。谢谢!...那些使用列表的人必须将树集转换为列表。 新的 ArrayList(treeSetListVariable)
猜你喜欢
  • 2015-10-19
  • 2012-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多