Existe-t-il un meilleur moyen de combiner deux ensembles de chaînes en java?

90

J'ai besoin de combiner deux ensembles de chaînes tout en filtrant les informations redondantes, c'est la solution que j'ai trouvée, y a-t-il une meilleure façon que quelqu'un puisse suggérer? Peut-être quelque chose de construit que j'ai négligé? Je n'ai pas eu de chance avec Google.

Set<String> oldStringSet = getOldStringSet();
Set<String> newStringSet = getNewStringSet();

for(String currentString : oldStringSet)
{
    if (!newStringSet.contains(currentString))
    {
        newStringSet.add(currentString);
    }
}
FooBar
la source

Réponses:

116

Comme a Setne contient pas d'entrées en double, vous pouvez donc combiner les deux en:

newStringSet.addAll(oldStringSet);

Ce n'est pas grave si vous ajoutez des choses deux fois, l'ensemble ne contiendra l'élément qu'une seule fois ... par exemple, il n'est pas nécessaire de vérifier en utilisant la containsméthode.

dacwe
la source
88

Vous pouvez le faire en utilisant ce one-liner

Set<String> combined = Stream.concat(newStringSet.stream(), oldStringSet.stream())
        .collect(Collectors.toSet());

Avec une importation statique, c'est encore plus joli

Set<String> combined = concat(newStringSet.stream(), oldStringSet.stream())
        .collect(toSet());

Une autre façon consiste à utiliser la méthode flatMap :

Set<String> combined = Stream.of(newStringSet, oldStringSet).flatMap(Set::stream)
        .collect(toSet());

De plus, toute collection pourrait facilement être combinée avec un seul élément

Set<String> combined = concat(newStringSet.stream(), Stream.of(singleValue))
        .collect(toSet());
ytterrr
la source
comment est-ce mieux que addAll?
KKlalala
7
@KKlalala, vos besoins détermineront ce qui est le mieux. La principale différence entre addAllet l'utilisation de Streams est: • l'utilisation set1.addAll(set2)aura pour effet secondaire de modifier physiquement le contenu de set1. • Cependant, l'utilisation de Streams entraînera toujours une nouvelle instance Setcontenant le contenu des deux ensembles sans modifier aucune des instances de l'ensemble d'origine. À mon humble avis, cette réponse est meilleure car elle évite les effets secondaires et le potentiel de modifications inattendues de l'ensemble d'origine s'il devait être utilisé ailleurs en attendant le contenu original. HTH
edwardsmatt
1
Cela a également l'avantage de prendre en charge les ensembles immuables. Voir: docs.oracle.com/javase/8/docs/api/java/util/…
edwardsmatt
34

La même chose avec la goyave :

Set<String> combinedSet = Sets.union(oldStringSet, newStringSet)
proactive-e
la source
2
Sets :: union est un excellent BinaryOperator à utiliser avec Collectors.reducing ().
mskfisher
12

Du jeu de définition contient uniquement des éléments uniques.

Set<String> distinct = new HashSet<String>(); 
 distinct.addAll(oldStringSet);
 distinct.addAll(newStringSet);

Pour améliorer votre code, vous pouvez créer une méthode générique pour cela

public static <T> Set<T> distinct(Collection<T>... lists) {
    Set<T> distinct = new HashSet<T>();

    for(Collection<T> list : lists) {
        distinct.addAll(list);
    }
    return distinct;
}
Damian Leszczyński - Vash
la source
6

Si vous utilisez Guava, vous pouvez également utiliser un constructeur pour obtenir plus de flexibilité:

ImmutableSet.<String>builder().addAll(someSet)
                              .addAll(anotherSet)
                              .add("A single string")
                              .build();
Léonard Bernardes
la source
4

Utilisez juste newStringSet.addAll(oldStringSet). Pas besoin de vérifier les doublons car l' Setimplémentation le fait déjà.

tobiasbayer
la source
3
 newStringSet.addAll(oldStringSet);

Cela produira l'union de s1 et s2

Kushan
la source
2

Utiliser boolean addAll(Collection<? extends E> c)
Ajoute tous les éléments de la collection spécifiée à cet ensemble s'ils ne sont pas déjà présents (opération facultative). Si la collection spécifiée est également un ensemble, l'opération addAll modifie effectivement cet ensemble afin que sa valeur soit l'union des deux ensembles. Le comportement de cette opération n'est pas défini si la collection spécifiée est modifiée pendant que l'opération est en cours.

newStringSet.addAll(oldStringSet)
Sumit Singh
la source
2

Si vous vous souciez des performances, et si vous n'avez pas besoin de conserver vos deux ensembles et que l'un d'eux peut être énorme, je vous suggère de vérifier quel ensemble est le plus grand et d'ajouter les éléments du plus petit.

Set<String> newStringSet = getNewStringSet();
Set<String> oldStringSet = getOldStringSet();

Set<String> myResult;
if(oldStringSet.size() > newStringSet.size()){
    oldStringSet.addAll(newStringSet);
    myResult = oldStringSet;
} else{
    newStringSet.addAll(oldStringSet);
    myResult = newStringSet;
}

De cette façon, si votre nouvel ensemble comporte 10 éléments et votre ancien ensemble en contient 100 000, vous ne faites que 10 opérations au lieu de 100 000.

Ricola
la source
C'est une très bonne logique que je ne peux pas imaginer pourquoi ce n'est pas dans le paramètre principal de la méthode addAll, commepublic boolean addAll(int index, Collection<? extends E> c, boolean checkSizes)
Gaspar
Je suppose qu'à cause de la spécification elle-même: ajoute tous les éléments de la collection spécifiée à cette collection . Vous pourriez avoir une autre méthode en effet, mais ce serait assez déroutant si elle ne suivait pas les mêmes spécifications que les méthodes qu'elle surcharge.
Ricola
Oui, je disais une autre méthode surchargeant celle-là
Gaspar
2

Si vous utilisez Apache Common, utilisez la SetUtilsclasse deorg.apache.commons.collections4.SetUtils;

SetUtils.union(setA, setB);
Vinit Solanki
la source
Notez que cela renvoie a SetView, qui est immuable.
jaco0646 le
2
Set.addAll()

Ajoute tous les éléments de la collection spécifiée à cet ensemble s'ils ne sont pas déjà présents (opération facultative). Si la collection spécifiée est également un ensemble, l'opération addAll modifie effectivement cet ensemble afin que sa valeur soit l'union des deux ensembles

newStringSet.addAll(oldStringSet)
UmNyobe
la source