Итак, давайте приступим к этому. Иногда вы обнаружите, что вам необходимо определить, какие элементы в одной коллекции существуют в другой, какие являются общими и / или которые не существуют в другой коллекции. В коллекциях Apache Commons есть несколько полезных методов в CollectionUtils , которые полезны, в частности, intersection (), но этот пост выходит за рамки вычисления уникальных элементов в коллекции коллекций, и всегда приятно перейти к деталям. Мы также сделаем решение более общим, поддерживая любое количество коллекций, а не только две коллекции, как это делает CollectionUtils . Кроме того, есть факт, что не все из нас выбирают или могут включать библиотеки только для того, чтобы получить пару полезных служебных методов.
Когда речь идет только о двух коллекциях, это не сложная проблема, но не все разработчики знакомы со всеми методами, которые определяет java.util.Collection , поэтому вот пример кода. Они используют вместе методы retainAll и removeAll для создания трех наборов — общего, присутствующего только в коллекции A, и присутствующего только в B.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
Set<String> a = new HashSet<String>();a.add("a");a.add("a2");a.add("common");Set<String> b = new HashSet<String>();b.add("b");b.add("b2");b.add("common");Set<String> inAOnly = new HashSet<String>(a);inAOnly.removeAll(b);System.out.println("A Only: " + inAOnly );Set<String> inBOnly = new HashSet<String>(b);inBOnly .removeAll(a);System.out.println("B Only: " + inBOnly );Set<String> common = new HashSet<String>(a);common.retainAll(b);System.out.println("Common: " + common); |
Выход:
|
1
2
3
|
A Only: [a, a2]B Only: [b, b2]Common: [common1] |
Обработка трех или более коллекций
Эта проблема немного сложнее при работе с более чем двумя коллекциями, но она может быть решена довольно просто, как показано ниже:
Вычисление общих элементов
Вычислить общие элементы легко, и этот код будет работать согласованно даже с большим количеством коллекций.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public static void main(String[] args) { List<String> a = Arrays.asList("a", "b", "c"); List<String> b = Arrays.asList("a", "b", "c", "d"); List<String> c = Arrays.asList("d", "e", "f", "g"); List<List<String>> lists = new ArrayList<List<String>>(); lists.add(a); System.out.println("Common in A: " + getCommonElements(lists)); lists.add(b); System.out.println("Common in A & B: " + getCommonElements(lists)); lists.add(c); System.out.println("Common in A & B & C: " + getCommonElements(lists)); lists.remove(a); System.out.println("Common in B & C: " + getCommonElements(lists));}public static <T> Set<T> getCommonElements(Collection<? extends Collection<T>> collections) { Set<T> common = new LinkedHashSet<T>(); if (!collections.isEmpty()) { Iterator<? extends Collection<T>> iterator = collections.iterator(); common.addAll(iterator.next()); while (iterator.hasNext()) { common.retainAll(iterator.next()); } } return common;} |
Выход:
|
1
2
3
4
|
Common in A: [a, b, c]Common in A & B: [a, b, c]Common in A & B & C: []Common in B & C: [d] |
Вычисление уникальных элементов
Вычисление уникальных элементов примерно так же просто, как вычисление общих элементов. Обратите внимание, что производительность этого кода будет ухудшаться при добавлении большого количества коллекций, хотя в большинстве случаев это не имеет значения. Я предполагаю, что есть способы, которыми это можно было бы оптимизировать, но, поскольку у меня не было проблемы, я не потрудился попробовать. Как сказал Кнут, как известно, «мы должны забыть о малой эффективности, скажем, в 97% случаев: преждевременная оптимизация — корень всех зол».
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public static void main(String[] args) { List<String> a = Arrays.asList("a", "b", "c"); List<String> b = Arrays.asList("a", "b", "c", "d"); List<String> c = Arrays.asList("d", "e", "f", "g"); List<List<String>> lists = new ArrayList<List<String>>(); lists.add(a); System.out.println("Unique in A: " + getUniqueElements(lists)); lists.add(b); System.out.println("Unique in A & B: " + getUniqueElements(lists)); lists.add(c); System.out.println("Unique in A & B & C: " + getUniqueElements(lists)); lists.remove(a); System.out.println("Unique in B & C: " + getUniqueElements(lists));}public static <T> List<Set<T>> getUniqueElements(Collection<? extends Collection<T>> collections) { List<Set<T>> allUniqueSets = new ArrayList<Set<T>>(); for (Collection<T> collection : collections) { Set<T> unique = new LinkedHashSet<T>(collection); allUniqueSets.add(unique); for (Collection<T> otherCollection : collections) { if (collection != otherCollection) { unique.removeAll(otherCollection); } } } return allUniqueSets;} |
Выход:
|
1
2
3
4
|
Unique in A: [[a, b, c]]Unique in A & B: [[], [d]]Unique in A & B & C: [[], [], [e, f, g]]Unique in B & C: [[a, b, c], [e, f, g]] |
Это все, что нужно сделать. Не стесняйтесь использовать этот код для любых целей, и если у вас есть какие-либо предложения или предложения по улучшению, оставьте комментарий. Все разработчики выигрывают, когда мы делимся знаниями и опытом.
Справка: Вычисление общих и уникальных элементов в нескольких коллекциях — Java & от нашего партнера JCG