Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как найти общие элементы и разницу двух списков

Короткий ответ

retainAll() оставляет в коллекции только элементы, которые есть во второй:

void main() {
    var a = new ArrayList<>(List.of(1, 2, 3, 4));
    var b = List.of(3, 4, 5);
 
    a.retainAll(b);
    IO.println(a);
}

Результат:

[3, 4]

Разница

removeAll() удаляет элементы, которые есть во второй коллекции — остаётся то, чего во второй нет:

void main() {
    var all = new ArrayList<>(List.of("Anna", "Oleg", "Boris"));
    var done = List.of("Oleg");
 
    all.removeAll(done);
    IO.println(all);
}

Результат:

[Anna, Boris]

Без изменения списков

Поток с HashSet создаёт новый список и не трогает исходные:

void main() {
    var a = List.of(1, 2, 3, 4);
    var b = new HashSet<>(List.of(3, 4, 5));
 
    IO.println(a.stream().filter(b::contains).toList());
    IO.println(a.stream().filter(n -> !b.contains(n)).toList());
}

Результат:

[3, 4]
[1, 2]

Симметричная разность

Элементы, которые есть только в одном из списков:

void main() {
    var a = new HashSet<>(List.of(1, 2, 3));
    var b = new HashSet<>(List.of(2, 3, 4));
 
    var onlyA = new TreeSet<>(a);
    onlyA.removeAll(b);
    var onlyB = new TreeSet<>(b);
    onlyB.removeAll(a);
    onlyA.addAll(onlyB);
    IO.println(onlyA);
}

Результат:

[1, 4]

Частая ошибка

Передавать большой List в retainAll() или filter(list::contains). Каждая проверка contains() у списка просматривает его целиком. Превратите вторую коллекцию в HashSet — это ускорит код в сотни раз на больших данных.

Функции из этого ответа

  • Set.retainAll() — Оставляет в множестве только элементы, которые есть в другой коллекции (пересечение).
  • List.remove() — Удаляет элемент списка по индексу или по значению.
  • HashSet — Множество без повторов на основе хеш-таблицы; порядок не гарантирован.
  • Stream.filter() — Оставляет в потоке только элементы, подходящие под условие.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.