web-dev-qa-db-fra.com

Quel est le meilleur moyen d'obtenir la différence symétrique entre deux ensembles en Java?

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 .

32
Simeon

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.

40
Philipp Wendler

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

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.

31
Don Roby

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);
4
Xavi López

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.

4
Erick Robertson

Solution Java 8

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. 

Java 11

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;
}
0
i_am_zero
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);
    }

}

0
Suraj Upreti