Część wspólna zbiorów z Guavą
Szybkie rozwiązanie problemu opisanego tutaj. Mamy dwa zbiory A i B, chcemy sprawdzić, czy wszystkie elementy ze zbioru A są obecne w zbiorze B. Najprościej jest to zrobić w następujący sposób:
Listing 1. Wykorzystanie API
public class SetsIntersectionExample {
public static void main(String[] args) {
// Smoki i gołe baby
Fairy fairy = Fairy.create();
Set<String> persons = Stream.generate(() -> fairy.person(PersonProperties.male())).limit(100)
.map(Person::firstName)
.collect(Collectors.toSet());
// Magia, bo chcemy mieć pewność, że mamy istniejące imiona.
Set<String> names = Sets.newHashSet((String) persons.toArray()[0], (String) persons.toArray()[1]);
// end: Smoki i gołe baby
System.out.println(persons);
System.out.println(names);
System.out.println(persons.containsAll(names));
}
}
Takie rozwiązanie podał Jakub Dyszkiewicz i prościej się nie da. Cytując dokumentację:
Returns true if this set contains all of the elements of the specified collection. If the specified collection is also a set, this method returns true if it is a subset of this set.
Przy czym jest, to dość słabo zaimplementowane:
Listing 2. AbstractCollection.containsAll wygląda tak:
public boolean containsAll(Collection<?> c) {
for (Object e : c)
if (!contains(e))
return false;
return true;
}
Sprawa trochę się komplikuje, gdy chcemy mieć informację o części wspólnej obu zbiorów. Tu jednak z pomocą przychodzi Guava, która ma klasę
narzędziową Sets
, która znowuż zawiera metodę intersection
:
Listing 3. Użycie Sets.intersection
public class SetsIntersectionExample {
public static void main(String[] args) {
// Smoki i gołe baby
Fairy fairy = Fairy.create();
Set<String> persons = Stream.generate(() -> fairy.person(PersonProperties.male())).limit(100)
.map(Person::firstName)
.collect(Collectors.toSet());
// Magia, bo chcemy mieć pewność, że mamy istniejące imiona.
Set<String> names = Sets.newHashSet((String) persons.toArray()[0], (String) persons.toArray()[1]);
// end: Smoki i gołe baby
System.out.println(persons);
System.out.println(names);
System.out.println(persons.containsAll(names));
System.out.println(Sets.intersection(persons, names).size() == names.size()); // to samo co wyżej
System.out.println(Sets.intersection(persons, names));
}
}
Implementacja jest w tym przypadku podobna (taka sama złożoność), ale trochę bardziej skomplikowana, bo wynikiem jest SetView
. Jedyny problem, jaki
będzie tu nas drażnił, to duże zbiory danych. W takim wypadku wyszukiwanie części wspólnej będzie długotrwałe.