Je me demande s'il existe un moyen rapide/propre pour obtenir la différence symétrique entre deux ensembles?
J'ai:
Set<String> s1 = new HashSet<String>();
s1.add("a");
s1.add("b");
s1.add("c");
Set<String> s2 = new HashSet<String>();
s2.add("b");
J'ai besoin de quelque chose comme:
Set<String> diff = Something.diff(s1, s2);
// diff would contain ["a", "c"]
Juste pour clarifier, j'ai besoin de la différence symétrique .
Vous pouvez utiliser certaines fonctions de la bibliothèque Google Guava (ce qui est vraiment génial, je le recommande vivement!):
Sets.difference(s1, s2);
Sets.symmetricDifference(s1, s2);
Javadocs pour difference () et symmetricDifference ()
symmetricDifference()
fait exactement ce que vous demandez , mais difference()
est également souvent utile.
Les deux méthodes renvoient une vue en direct, mais vous pouvez par exemple appeler .immutableCopy()
sur le jeu résultant pour obtenir un jeu non modifiable. Si vous ne voulez pas de vue, mais avez besoin d'une instance définie que vous puissiez modifier, appelez .copyInto(s3)
. Voir SetView pour ces méthodes.
Vous voulez la différence symétrique .
public static <T> Set<T> diff(final Set<? extends T> s1, final Set<? extends T> s2) {
Set<T> symmetricDiff = new HashSet<T>(s1);
symmetricDiff.addAll(s2);
Set<T> tmp = new HashSet<T>(s1);
tmp.retainAll(s2);
symmetricDiff.removeAll(tmp);
return symmetricDiff;
}
Si vous voulez une bibliothèque, Apache Commons CollectionUtils has
CollectionUtils.disjunction(s1, s2)
qui retourne une Collection
non générique.
et Ensembles de goyave a
Sets.symmetricDifference(s1, s2)
qui retourne une Set
non modifiable sous la forme d'un Sets.SetView
générique.
Le goyave est un peu plus moderne, prenant en charge les génériques, mais l'un ou l'autre fonctionnera.
Si vous pouvez utiliser Apache-Commons Collections , vous recherchez CollectionUtils.disjunction(Collection a, Collection b)
. Il renvoie la différence symétrique des deux collections.
Sinon, soustrayez (removeAll
) l'intersection (retainAll
) des deux ensembles avec l'union des deux (addAll
):
Set<String> intersection = new HashSet<String>(set1);
intersection.retainAll(set2);
Set<String> difference = new HashSet<String>();
difference.addAll(set1);
difference.addAll(set2);
difference.removeAll(intersection);
Boucle à travers un ensemble et comparer.
Il n’ya que O(n)
pour parcourir l’un des ensembles. Considérons ce code:
for (String key: oldSet) {
if (newSet.contains(key))
newSet.remove(key);
else
newSet.add(key);
}
Et la newSet
ne contiendra plus que les entrées uniques des deux ensembles. C'est rapide, car il vous suffit de parcourir les éléments de l'un des ensembles et de créer des ensembles à moins d'en avoir explicitement besoin.
Nous pouvons écrire deux méthodes utilitaires (pour Java 8 et les versions antérieures) dans une classe SetUtils (say)
comme:
public static <T> Set<T> symmetricDifferenceJava8(final Set<T> setOne, final Set<T> setTwo) {
Set<T> result = new HashSet<>(setOne);
setTwo.stream().filter(not(resultSet::add)).forEach(resultSet::remove);
return result;
}
public static <T> Set<T> symmetricDifference(final Set<T> setOne, final Set<T> setTwo) {
Set<T> result = new HashSet<T>(setOne);
for (T element : setTwo) {
if (!result.add(element)) {
result.remove(element);
}
}
return result;
}
public static <T> Predicate<T> not(Predicate<T> t) {
return t.negate();
}
La méthode add
renvoie false si l'élément existe déjà et que la méthode negate est utilisée pour annuler le prédicat.
Nous avons une méthode Predicate # not pour prédicat en Java 11 et pouvons l’utiliser comme:
public static <T> Set<T> symmetricDifferenceJava11(final Set<T> setOne, final Set<T> setTwo) {
Set<T> result = new HashSet<>(setOne);
setTwo.stream().filter(Predicate.not(resultSet::add)).forEach(resultSet::remove);
return result;
}
public class Practice {
public static void main(String[] args) {
Set<Integer> set1 = new HashSet<Integer>();
Set<Integer> set2 = new HashSet<Integer>();
set1.add(1);
set1.add(4);
set1.add(7);
set1.add(9);
set2.add(2);
set2.add(4);
set2.add(5);
set2.add(6);
set2.add(7);
symmetricSetDifference(set1, set2);
}
public static void symmetricSetDifference(Set<Integer>set1, Set<Integer>set2){
//creating a new set
Set<Integer> newSet = new HashSet<Integer>(set1);
newSet.removeAll(set2);
set2.removeAll(set1);
newSet.addAll(set2);
System.out.println(newSet);
}
}