Эффективное пересечение двух List <String>в Java? - PullRequest
58 голосов
/ 08 марта 2010

Вопрос прост:

У меня есть два списка

List<String> columnsOld = DBUtils.GetColumns(db, TableName);
List<String> columnsNew = DBUtils.GetColumns(db, TableName);

И мне нужно пересечь их. Есть ли быстрый способ добиться этого?

Ответы [ 8 ]

108 голосов
/ 08 марта 2010

Вы можете использовать retainAll метод:

columnsOld.retainAll (columnsNew);
18 голосов
/ 08 марта 2010

Поскольку retainAll не будет касаться набора аргументов, это будет быстрее:

List<String> columnsOld = DBUtils.GetColumns(db, TableName); 
List<String> columnsNew = DBUtils.GetColumns(db, TableName); 

for(int i = columnsNew.size() - 1; i > -1; --i){
    String str = columnsNew.get(i);
    if(!columnsOld.remove(str))
        columnsNew.remove(str);
}

Пересечением будут значения, оставленные в столбцах New. Удаление уже сравниваемых значений из столбцов Старое сократит количество необходимых сравнений.

16 голосов
/ 28 марта 2013

Использование гуавы:

Sets.intersection(Sets.newHashSet(setA), Sets.newHashSet(setB))

Google Guava Library

8 голосов
/ 06 января 2013

Как насчет

private List<String> intersect(List<String> A, List<String> B) {
    List<String> rtnList = new LinkedList<>();
    for(String dto : A) {
        if(B.contains(dto)) {
            rtnList.add(dto);
        }
    }
    return rtnList;
}
2 голосов
/ 11 сентября 2014

Есть хороший способ с потоками, которые могут сделать это в одной строке кода, и вы можете создать два списка, которые не принадлежат к одному и тому же типу, что невозможно с методом containsAll afaik:

columnsOld.stream().filter(c -> columnsNew.contains(c)).collect(Collectors.toList());

Пример для списков с разными типами. Если у вас есть связь между foo и bar, и вы можете получить bar-объект из foo, вы можете изменить свой поток:

List<foo> fooList = new ArrayList<>(Arrays.asList(new foo(), new foo()));
List<bar> barList = new ArrayList<>(Arrays.asList(new bar(), new bar()));

fooList.stream().filter(f -> barList.contains(f.getBar()).collect(Collectors.toList());
1 голос
/ 07 мая 2016

Если вы поместите второй список в набор, скажем, HashSet. И просто повторяйте первый список, проверяя наличие на множестве и удаляя, если его нет, ваш первый список в конечном итоге будет иметь необходимое пересечение. Это будет намного быстрее, чем retainAll или содержится в списке. Акцент здесь делается на использование набора вместо списка. Поиски O (1). firstList.retainAll (новый HashSet (secondList)) также будет работать.

0 голосов
/ 09 апреля 2019

использовать org.apache.commons.collections4.ListUtils # пересечение

0 голосов
/ 09 ноября 2016

с использованием retainAll, если не волнует случаи, в противном случае используется N.intersection

a = N.asList(12, 16, 16, 17, 19);
b = N.asList(16, 19, 107);
a.retainAll(b); // [16, 16, 19]
N.println(a);

a = N.asList(12, 16, 16, 17, 19);
b = N.asList(16, 19, 107);
a = N.intersect(a, b);
N.println(a); // [16, 19]

N - это служебный класс в AbacusUtil

...