Reputation: 4271
I have this list:
private List<Set<Address>> scanList;
So my list contains multiple scans as you can see. After each scan I add new set into the list.
After all scans are finished I would like to take only the addresses that occur in every set and put it into:
private List<Address> addresses;
Does something like this already exists in Set/TreeSet/HashSet?
EDIT: after answers, retainAll() is the right method. Thank you. Here is the source:
Set<Address> addressCross = scanList.get(0);
for (int i = 1; i < scanList.size(); i++) {
addressCross.retainAll(scanList.get(i));
}
for (Address address : addressCross) {
addresses.add(address);
}
Upvotes: 26
Views: 24927
Reputation: 4648
There's another nice solution over here: https://stackoverflow.com/a/38266681/349169
Set<Address> intersection = scanList.stream()
.skip(1) // optional
.collect(()->new HashSet<>(scanList.get(0)), Set::retainAll, Set::retainAll);
For example, in modern Java:
record Address( String street ) { }
List < Set < Address > > listOfSetsOfAddresses =
List.of ( // Only the tree-species are in common, Oak & Maple.
Set.of ( new Address ( "Oak" ) , new Address ( "Maple" ) , new Address ( "Broad" ) ) ,
Set.of ( new Address ( "Main" ) , new Address ( "Maple" ) , new Address ( "Oak" ) ) ,
Set.of ( new Address ( "Oak" ) , new Address ( "Meridian" ) , new Address ( "Maple" ) )
);
Set < Address > intersection =
listOfSetsOfAddresses
.stream ( )
.skip ( 1 )
.collect (
( ) -> new HashSet <> ( listOfSetsOfAddresses.getFirst ( ) ) ,
Set :: retainAll ,
Set :: retainAll
);
System.out.println ( "intersection.toString() = " + intersection );
intersection.toString() = [Address[street=Oak], Address[street=Maple]]
Upvotes: 1
Reputation: 1016
retainAll
Use Set#retainAll
or List#retainAll()
to get an intersection.
To quote the Javadoc:
Retains only the elements in this list that are contained in the specified collection (optional operation). In other words, removes from this list all of its elements that are not contained in the specified collection.
For example code using streams, see Answer by Chris.
Upvotes: 13
Reputation: 110046
With Guava, you could do it like this:
Set<Address> intersection = scanList.get(0);
for (Set<Address> scan : scanList.subList(1, scanList.size())) {
intersection = Sets.intersection(intersection, scan);
}
List<Address> addresses = Lists.newArrayList(intersection);
This creates a view of the intersection of all the sets in the scanList
and then copies the addresses in the intersection into a List
. You would need to ensure your scanList
has at least one element in it, of course.
Upvotes: 8
Reputation: 133567
you can use retainAll(Collection<?> c)
, check it out here
A side note: that operation is called intersection.
To convert then it to a List
you can use the method addAll(Collection<? extends E> c)
which should work between all kinds of containers.
eg:
ArrayList<Address> list = new ArrayList<Address>();
list.addAll(yourSet);
Upvotes: 16