Общие элементы в двух списках


97

У меня есть два 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 возвращает новый список? Я попытался сохранить вывод сохранения в новый список, например, 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 таких же элемента. keepAll возвращает 3 элемента в l3, даже если он содержится только дважды в l1.
demongolem

35

Зачем изобретать велосипед? Используйте коллекции Commons :

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

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

18

Использование Stream.filter()метода Java 8 в сочетании с 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
Contains выглядит так, будто это будет операция O (n), которая будет вызываться n раз, если компилятор не сделает что-то умное. Кто-нибудь знает, выполняется ли вышеупомянутое в линейном или квадратичном времени?
Regorsmitz

1
Это была бы * п операция!
Lakshmikant Deshpande

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); Список <Целое число> listB = asList (1, 5, 6, 7);
Rajeev Ranjan

4

Вы можете получить общие элементы между двумя списками, используя метод keepAll. Этот метод удалит все несовпадающие элементы из списка, к которому он применяется.

Ex.: list.retainAll(list1);

В этом случае из списка будут удалены все элементы, которых нет в списке list1, и останутся только те элементы, которые являются общими для list и list1.

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]

ПРИМЕЧАНИЕ. После применения метода keepAll к списку список содержит общий элемент между списком и списком list1.


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 и 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
OP просил найти способ узнать, какие элементы были общими, а не сколько общих элементов.
Брендон Дуган

@BrendonDugan - вот что делает этот код. Список commonsсодержит общие элементы. Второй цикл for печатает их на консоли. Я не вижу, где код считает общие элементы.
Ajoy Bhatia,

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

@BrendonDugan О, хорошо. Извини за это. Я должен иметь в виду, что ответ можно редактировать на месте, но комментарии обычно оставляют как есть, в хронологическом порядке :-)
Ajoy Bhatia

0

Некоторые из приведенных выше ответов похожи, но не совпадают, поэтому опубликуйте их как новый ответ.

Решение:
1. Используйте HashSet для хранения элементов, которые необходимо удалить
2. Добавьте все элементы list1 в HashSet
3. Выполните итерацию list2 и удалите элементы из HashSet, которые присутствуют в list2 ==>, которые присутствуют как в list1, так и в list2
4 . Теперь переберите HashSet и удалите элементы из list1 (поскольку мы добавили все элементы list1 для установки), наконец, list1 имеет все общие элементы.
Примечание: мы можем добавить все элементы list2, и на третьей итерации мы должны удалить элементы из список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.