Есть ли способ найти общие элементы в нескольких списках?

У меня есть список целых массивов. Мне нужно найти общие элементы между ними. Что я могу придумать, так это расширение того, что указано в Общие элементы в двух списках< /сильный>

Example would be 
[1,3,5],
[1,6,7,9,3],
[1,3,10,11]

should result in [1,3]

В массивах также нет дубликатов.

Есть ли прямой способ сделать это?


person ravindrab    schedule 03.03.2013    source источник
comment
Вы пытаетесь пересечь значения списка массивов int? Что вы подразумеваете под прямым путем?   -  person Zach Latta    schedule 03.03.2013
comment
Общее значение, что они появляются в каждом списке или в более чем одном списке?   -  person NPE    schedule 03.03.2013
comment
Я имел в виду прямолинейный метод в какой-то библиотеке, такой как apache commons, colt, guava и т. д.   -  person ravindrab    schedule 03.03.2013
comment
Вы можете перебирать все элементы в каждом массиве и заполнять Map. Где ключ — это ваше целочисленное значение, а значение — счетчик того, сколько раз встречается этот элемент.   -  person Mike    schedule 03.03.2013


Ответы (6)


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

person Amir Kost    schedule 03.03.2013
comment
верно, но мое требование - получить общие элементы для нескольких списков - person ravindrab; 04.03.2013
comment
Он по-прежнему соответствует вашим требованиям - вы можете преобразовать каждый список в набор (HashSet может принимать коллекцию в качестве аргумента конструктора), выполнить пересечение и преобразовать пересекаемый набор обратно в список. Это решение — O(n), тогда как сортировка каждого списка и сравнение — O(n*log(n)), а сравнение каждого элемента с другими — O(n^2). - person Amir Kost; 05.03.2013
comment
Преобразование @AmirKost в Set (это не LinkedHashSet) приведет к потере порядка в списке. - person wchargin; 25.02.2014

Вы можете использовать метод пересечения Set, предлагаемый Guava. Вот небольшой пример:

public <T> Set<T> intersection(List<T>... list) {
    Set<T> result = Sets.newHashSet(list[0]);
    for (List<T> numbers : list) {
        result = Sets.intersection(result, Sets.newHashSet(numbers));
    }
    return result;
}

Надеюсь, что это может помочь вам

person Oussama Zoghlami    schedule 05.03.2013
comment
это мне очень помогло спасибо за решение. Интересно, почему это неприемлемо, в любом случае, спасибо - person kinsley kajiva; 16.07.2017

Мы можем использовать retainAll метод коллекций. Я инициализировал свой массив commons с помощью первого списка массивов и вызвал его для каждого оставшегося списка массивов.

    List<List<Integer>> lists = new ArrayList<List<Integer>>();
    lists.add(new ArrayList<Integer>(Arrays.asList(1, 3, 5)));
    lists.add(new ArrayList<Integer>(Arrays.asList(1, 6, 7, 9, 3)));
    lists.add(new ArrayList<Integer>(Arrays.asList(1, 3, 10, 11)));

    List<Integer> commons = new ArrayList<Integer>();
    commons.addAll(lists.get(1));
    for (ListIterator<List<Integer>> iter = lists.listIterator(1); iter.hasNext(); ) {
        commons.retainAll(iter.next());
    }

    System.out.println(commons);
    System.out.println(lists.get(1));
person Han Tuzun    schedule 01.10.2014
comment
Почему вы начинаете с индекса 1? Разве мы не должны начать с 0? - person Chen Ni; 25.06.2020

с Явой 8

ArrayList retain = list1.stream()
                     .filter(list2::contains).filter(list3::contains).collect(toList())
person Rohit Jain    schedule 02.10.2018
comment
Я думаю, что это должно быть принято, хотя я думаю, что правильная форма: ArrayList retain = list1.stream().filter(list2::contains).collect(Collectors.toCollection(ArrayList::new)); - person WesternGun; 13.12.2018
comment
это работает только с 3 списками. Я думаю, что вопрос о произвольном количестве списков. - person TriCore; 12.05.2021

Если вы ищете функцию, которая возвращает элементы, существующие во всех списках,

тогда прямой и простой способ - построить статистику { ‹ член, вхождения > }

Условие здесь - отсутствие дубликатов в одном списке,

private Set<Integer> getCommonElements(ArrayList<Integer[]> idList)
{

    MapList<Integer,Short> stat = new MapList<Integer,Short>();

    // Here we count how many times each value occur
    for (int i = 0; i < idList.size(); i++)
    {
        for (int j = 0; j < idList.get(i).size; j++)
        {
            if (stat.containsKey(idList.get(i)[j]))
            {
                stat.set(idList.get(i)[j], stat.get(idList.get(i)[j])+1);
            }
            else
            {
                stat.add(idList.get(i)[j], 1);
            }
        }
    }

    // Here we only keep value that occured in all lists
    for (int i = 0; i < stat.size(); i++)
    {
        if (stat.get(i) < idList.size())
        {
            stat.remove(i);
            i--;
        }
    }

    return stat.keySet();
}
person Khaled.K    schedule 03.03.2013
comment
В отличие от C#, в Java нельзя указать примитив как универсальный тип. Поэтому вместо Set<int> используйте Set<Integer>. - person Eng.Fouad; 03.03.2013
comment
Спасибо за информацию, Фуад - person Khaled.K; 06.03.2013

person    schedule
comment
Пожалуйста, объясните, как работает этот код, и ответьте на вопрос. - person Null; 02.03.2021
comment
Дампы кода не дают хороших ответов. Вы должны объяснить, как и почему это решает их проблему. Я рекомендую прочитать Как написать хороший ответ?. Это может помочь будущим пользователям изучить и в конечном итоге применить эти знания к своему собственному коду. Вы также, вероятно, получите положительные отзывы / голоса от пользователей, когда код будет объяснен. - person John Conde; 02.03.2021