Загальні елементи у двох списках


95

У мене є два ArrayListоб’єкти з трьома цілими числами в кожному. Я хочу знайти спосіб повернути загальні елементи двох списків. Хтось уявляє, як я можу цього досягти?

Відповіді:


161

Використовуйте Collection#retainAll().

listA.retainAll(listB);
// listA now contains only the elements which are also contained in listB.

Якщо ви хочете уникнути впливу на зміни listA, вам потрібно створити нову.

List<Integer> common = new ArrayList<Integer>(listA);
common.retainAll(listB);
// common now contains only the elements which are contained in listA and listB.

RetainAll повертає новий список? Я спробував зберегти висновок retain у новому списку, наприклад, тим, що tempList.addAll (listA.retainAll (listB)); але це не працює
зеніт

1
Як відповіли за посиланням позаду Collection#retainAll()та коментарями до фрагментів коду, ні, це не так. Зміни відображаються у списку, до якого ви викликаєте метод.
BalusC

Проблема полягає в тому, що спільний список ініціалізується з розміром 3, потім ви намагаєтесь змінити його розмір, повернувши лише один або два елементи. Я пробую те, що ви пропонуєте, і це повертає мене поза межами винятку.
зеніт

При такому підході я не зможу зрівняти номер входження елемента ....... скажімо, наприклад, listA {2,3,5} і listB {5 5}, якщо я зроблю listB.retainAll (listA) , listB тепер матиме {5,5} ...... Я хочу свій кінцевий результат після порівняння listA та listB як {5}. Будь ласка, підкажіть, як ми можемо цього досягти
НЕНСІ

1
Якщо зробити це з поганим вибором об'єкта колекції, це може кинути UnsupportedOperationException. Наведений вище приклад з ArrayList справді працює.
demongolem

39

Ви можете використовувати встановлені операції перетину зі своїми ArrayListоб’єктами.

Щось на зразок цього:

List<Integer> l1 = new ArrayList<Integer>();

l1.add(1);
l1.add(2);
l1.add(3);

List<Integer> l2= new ArrayList<Integer>();
l2.add(4);
l2.add(2);
l2.add(3);

System.out.println("l1 == "+l1);
System.out.println("l2 == "+l2);

List<Integer> l3 = new ArrayList<Integer>(l2);
l3.retainAll(l1);

    System.out.println("l3 == "+l3);

Тепер l3має містити лише спільні елементи між l1і l2.

CONSOLE OUTPUT
l1 == [1, 2, 3]
l2 == [4, 2, 3]
l3 == [2, 3]

6
Зауважте, що таким чином зміни відображаються і в l2. Ви, мабуть, хотіли сказати List<Integer> l3 = new ArrayList<Integer>(l2);замість цього.
BalusC

Проблема стає трохи менш, якщо скажімо, у l1 є 2 елемента, а в l2 було 3 цього самого елемента. retainAll повертає вміщує 3 цього елемента в l3, хоча він міститься лише двічі в l1.
demongolem

35

Навіщо винаходити колесо? Використовуйте колекції Commons :

CollectionUtils.intersection(java.util.Collection a, java.util.Collection b)

Це чудове рішення, проте, як я вже згадував вище, воно має іншу поведінку, ніж retainAll()у повторюваних елементів. Тож, швидше за все, один правильний, а другий неправильний, залежно від того, як ви підходите до проблеми.
demongolem

18

Використання методу Java 8 Stream.filter()у поєднанні з List.contains():

import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;

/* ... */

List<Integer> list1 = asList(1, 2, 3, 4, 5);
List<Integer> list2 = asList(1, 3, 5, 7, 9);

List<Integer> common = list1.stream().filter(list2::contains).collect(toList());

4
Здається, схоже, що це буде операція O (n), яка буде викликана n разів, якщо компілятор не зробить щось розумне. Хтось знає, чи працює це вище в лінійний чи квадратний час?
Regorsmitz

1
Це була б * n операція!
Лакшмікант Дешпанде

5

введіть тут опис зображення

            List<String> lista =new ArrayList<String>();
            List<String> listb =new ArrayList<String>();

            lista.add("Isabella");
            lista.add("Angelina");
            lista.add("Pille");
            lista.add("Hazem");

            listb.add("Isabella");
            listb.add("Angelina");
            listb.add("Bianca");

            // Create an aplusb list which will contain both list (list1 and list2) in which common element will occur twice 
            List<String> listapluslistb =new ArrayList<String>(lista);    
            listapluslistb.addAll(listb);

            // Create an aunionb set which will contain both list (list1 and list2) in which common element will occur once
            Set<String> listaunionlistb =new HashSet<String>(lista);
            listaunionlistb.addAll(listb);

            for(String s:listaunionlistb)
            {
                listapluslistb.remove(s);
            }
            System.out.println(listapluslistb);

Хоча цей код може відповісти на запитання, надання додаткового контексту щодо того, як та / або чому він вирішує проблему, покращило б довгострокову цінність відповіді.
Майкл Паркер,

5
List<Integer> listA = new ArrayList<>();
    listA.add(1);
    listA.add(5);
    listA.add(3);
    listA.add(4);   

List<Integer> listB = new ArrayList<>();
    listB.add(1);
    listB.add(5);
    listB.add(6);
    listB.add(7);
System.out.println(listA.stream().filter(listB::contains).collect(Collectors.toList()));


Java 1.8 Stream API Solutions

Вихід [1, 5]


-Вдосконалення ми можемо визначити список як List <Integer> listA = asList (1, 5, 3, 4); Список <Integer> listB = asList (1, 5, 6, 7);
Радєєв Ранджан

4

Ви можете отримати загальні елементи між двома списками, використовуючи метод "retainAll". Цей метод видалить усі незрівняні елементи зі списку, до якого він застосовується.

Ex.: list.retainAll(list1);

У цьому випадку зі списку всі елементи, яких немає в списку1, будуть видалені, а залишаться лише ті, що є спільними між списком та списком1.

List<Integer> list = new ArrayList<>();
list.add(10);
list.add(13);
list.add(12);
list.add(11);

List<Integer> list1 = new ArrayList<>();
list1.add(10);
list1.add(113);
list1.add(112);
list1.add(111);
//before retainAll
System.out.println(list);
System.out.println(list1);
//applying retainAll on list
list.retainAll(list1);
//After retainAll
System.out.println("list::"+list);
System.out.println("list1::"+list1);

Вихід:

[10, 13, 12, 11]
[10, 113, 112, 111]
list::[10]
list1::[10, 113, 112, 111]

ПРИМІТКА. Після того, як retainAll застосовано до списку, список містить загальний елемент між списком та списком1.


4
public <T> List<T> getIntersectOfCollections(Collection<T> first, Collection<T> second) {
        return first.stream()
                .filter(second::contains)
                .collect(Collectors.toList());
    }

3
    // Create two collections:
    LinkedList<String> listA =  new LinkedList<String>();
    ArrayList<String> listB =  new ArrayList<String>();

    // Add some elements to listA:
    listA.add("A");
    listA.add("B");
    listA.add("C");
    listA.add("D");

    // Add some elements to listB:
    listB.add("A");
    listB.add("B");
    listB.add("C");

    // use 

    List<String> common = new ArrayList<String>(listA);
    // use common.retainAll

    common.retainAll(listB);

    System.out.println("The common collection is : " + common);

3

розглянемо два списки L1 ans L2

За допомогою Java8 ми легко можемо це дізнатись

L1.stream().filter(L2::contains).collect(Collectors.toList())


1

У випадку, якщо ви хочете зробити це самостійно ..

List<Integer> commons = new ArrayList<Integer>();

for (Integer igr : group1) {
    if (group2.contains(igr)) {
        commons.add(igr);
    }
}

System.out.println("Common elements are :: -");
for (Integer igr : commons) {
    System.out.println(" "+igr);
}

1
ОП запитував спосіб знайти, які елементи є загальними, а не скільки загальних елементів.
Брендон Даган

@BrendonDugan - саме це і робить цей код. Список commonsмістить загальні елементи. Друга for-loop друкує їх на консолі. Я не бачу, де в коді підраховуються загальні елементи.
Радійте Бхатії

@AjoyBhatia - Коли я зробив свій коментар (у 2013 році), код повернув лише кількість загальних елементів.
Брендон Дуган

@BrendonDugan О, гаразд. Вибач за це. Я маю пам’ятати, що відповідь можна редагувати на місці, але коментарі, як правило, залишаються як є, у хронологічному порядку :-)
Радійте Бхатії

0

Деякі з наведених вище відповідей схожі, але не однакові, тому розміщуєте їх як нову відповідь.

Рішення:
1. Використовуйте HashSet для утримання елементів, які потрібно видалити
2. Додайте всі елементи list1 до HashSet
3. ітератуйте list2 та видаліть елементи з HashSet, які є у list2 ==>, які присутні як у list1, так і в list2
4 Тепер повторіть HashSet і видаліть елементи з list1 (оскільки ми додали всі елементи list1 до набору), нарешті, list1 має всі загальні елементи
Примітка: Ми можемо додати всі елементи list2, а в 3-ій ітерації ми повинні видалити елементи з список2.

Складність часу: O (n)
Складність простору: O (n)

Код:

import com.sun.tools.javac.util.Assert;
import org.apache.commons.collections4.CollectionUtils;

    List<Integer> list1 = new ArrayList<>();
    list1.add(1);
    list1.add(2);
    list1.add(3);
    list1.add(4);
    list1.add(5);

    List<Integer> list2 = new ArrayList<>();
    list2.add(1);
    list2.add(3);
    list2.add(5);
    list2.add(7);
    Set<Integer> toBeRemoveFromList1 = new HashSet<>(list1);
    System.out.println("list1:" + list1);
    System.out.println("list2:" + list2);
    for (Integer n : list2) {
        if (toBeRemoveFromList1.contains(n)) {
            toBeRemoveFromList1.remove(n);
        }
    }
    System.out.println("toBeRemoveFromList1:" + toBeRemoveFromList1);
    for (Integer n : toBeRemoveFromList1) {
        list1.remove(n);
    }
    System.out.println("list1:" + list1);
    System.out.println("collectionUtils:" + CollectionUtils.intersection(list1, list2));
    Assert.check(CollectionUtils.intersection(list1, list2).containsAll(list1));

вихід:

list1:[1, 2, 3, 4, 5]
list2:[1, 3, 5, 7]
toBeRemoveFromList1:[2, 4]
list1:[1, 3, 5]
collectionUtils:[1, 3, 5]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.