Take the intersection of multiple collections in Java - retainAll()

Intersection of multiple collections in Java

The retainAll() method is defined in the Collection interface

retainAll()

Retains only the elements in this set that are contained in the specified collection (optional operation). In other words, removes from this set all of its elements that are not contained in the specified collection. If the specified collection is also a set, this operation effectively modifies this set so that its value is the intersection of the two sets.

In simple terms, the purpose of this method is to take an intersection of the current collection and the collection specified by the parameter , and modify the current collection to keep only the intersection elements.

The following figure is an architectural diagram of the collection class framework:
insert image description here

Through this architecture diagram, you can have a clear positioning of the collection class in your brain.

The retainAll() method is implemented in the abstract class AbstractCollection.
Using the retainAll() method of the Set collection is actually calling the retainAll() method in the AbstractCollection.

The bottom layer actually uses the contains() method to determine whether the element exists in the collection. Traverse the elements in the current collection, judge whether each element exists in the parameter collection, if not, remove the element from the current collection, and finally retain the common elements of the two collections.

public boolean retainAll(Collection<?> c) {
    
    
        Objects.requireNonNull(c);
        boolean modified = false;
        Iterator<E> it = iterator();
        while (it.hasNext()) {
    
    
            if (!c.contains(it.next())) {
    
    
                it.remove();
                modified = true;
            }
        }
        return modified;
    }

For the ArrayList class, the retainAll() method is overridden. The core idea is the same.

public boolean retainAll(Collection<?> c) {
    
    
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }

    private boolean batchRemove(Collection<?> c, boolean complement) {
    
    
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
    
    
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
    
    
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
    
    
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            if (w != size) {
    
    
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }

Take the intersection of multiple sets (uncertain number of sets)

Idea:
Create a new List collection, put all the target collections into the newly created List collection, if conditional filtering is available, use the stream stream for conditional filtering (such as removing empty collections), and finally get the result List collection.
Then traverse the set, use the first set in the set to intersect with each subsequent set in turn, and you can get the intersection of all sets.

Set set1 = new HashSet();
Set set2 = new HashSet();
Set set3 = new HashSet();

set1.add("1");
set2.add("1");
set2.add("2");
set3.add("1");

List<Set> setList = new ArrayList<>();
setList.add(set1);
setList.add(set2);
setList.add(set3);

//List<Set> resultSetList = setList.stream().filter(Objects::nonNull).collect(Collectors.toList());

Set resultSet = setList.get(0);
resultSetList.forEach(item -> {
    
    
    resultSet.retainAll(item);
});

//resultSet 结果仅包含 1

No matter how complicated things are, they are composed of simple things, only because of quantitative changes to qualitative changes.

Guess you like

Origin blog.csdn.net/weixin_40307206/article/details/121621944