Пересечение двух объектов списков в java 8

Пересечение двух объектов списков в 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)));

person Myjay1516    schedule 16.12.2018    source источник
comment
каков результат, который вы ожидаете? что вы считаете неправильным? это кстати не понятно   -  person Naman    schedule 16.12.2018
comment
Поскольку List может содержать один и тот же элемент несколько раз, при пересечении списков, если A содержит элемент x трижды, а B содержит элемент x дважды, сколько раз вы ожидаете ответ в конечном списке? 3? 2? 1? Это определит, какой из этих подходов работает.   -  person Brian Goetz    schedule 17.12.2018


Ответы (2)


Может кто-нибудь сказать мне, что я делаю неправильно?

Вы нарушаете Побочные эффекты принцип java -stream, который в двух словах говорит о том, что поток не должен изменять другую коллекцию при выполнении действий через конвейеры. Я не тестировал ваш код, однако вы не должны так обращаться с потоками.


Как сделать это лучше?

Просто используйте List::contains в предикате фильтра, чтобы избавиться от уникальных значений.

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

Это решение (понимание метода List::contains) основан на реализованном сравнении на равенство с использованием Object::equals. Следовательно, необходимо переопределить тот же самый метод в классе Student.

Редактировать: имейте в виду, что автоматическое переопределение Object::equals будет учитывать id для вычисления равенства. Поэтому равенство будет основано только на имени и фамилии. (спасибо @nullpointer).

Без переопределения Object::equals?

Вы должны выполнить сравнение в filter, используя другой stream и метод Stream::anyMatch, который возвращает 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());
person Nikolas Charalambidis    schedule 16.12.2018
comment
это определенно потребует сравнения объектов. также тот факт, что последнее значение атрибута изменяется в двух предоставленных примерных списках, вывод здесь будет отличаться от того, что ожидается в вопросе. - person Naman; 16.12.2018
comment
Я имел в виду, что если я изменю originalStudent.add(new Student("Jonathan", "Edwards",2)); на originalStudent.add(new Student("Jonathan", "Edwards",7));, ваш первый блок кода не будет давать такой же результат, как ваше последнее предложение. - person Naman; 16.12.2018
comment
Плюс один за решение с anyMatch и collect :) - person Naman; 16.12.2018
comment
@ Myjay1516 Myjay1516, почему это не принятый ответ? :/ - person Scaramouche; 17.06.2019

Что вы можете сделать, так это создать SortedSet<Student> из двух соединенных списков originalStudent и newStudent. Отсортированный набор использует 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))
    ))
person HPH    schedule 17.12.2018
comment
У меня работает нормально. Спасибо!... Те, кто работает со списком, должны преобразовать набор деревьев в список. новый ArrayList‹Student›(treeSetListVariable) - person Rahul Dudhane; 11.03.2020