web-dev-qa-db-fra.com

Initialiser un Set avec un Iterable

Je souhaite initialiser une implémentation d'ensemble (HashSet) en Java avec un Iterable. Cependant, le constructeur de HashSet n'accepte pas les Iterables, mais uniquement les objets de type Collections.

Existe-t-il un moyen de convertir Iterable en un sous-type de Collections?.

15
VaidAbhishek

HashSet constructeur repose sur plus que ce que Iterable offre: il veut connaître la size de la collection à l’avance afin de construire de manière optimale la HashMap sous-jacente. Si vous avez une Iterable austère vraie, qui ne connaît pas sa taille, vous devrez alors réaliser la Iterable à l’avance en la transformant en une Collection régulière de plusieurs façons évidentes.

Si, par contre, vous avez un objet plus riche qui connaît déjà sa taille, il serait alors avantageux de créer une classe d'adaptateur minimaliste qui enveloppe votre Iterable dans une collection, en implémentant simplement size en plus de transmettre l'appel à iterator.

public class IterableCollection<T> implements Collection<T>
{
   private final Iterable<T> iterable;

   public IterableCollection(Iterable<T> it) { this.iterable = it; }

   @Override public Iterator<T> iterator() { return iterable.iterator(); }

   @Override public int size() { return ... custom code to determine size ... }

   @Override .... all others ... { throw new UnsupportedOperationException(); }
}
6
Marko Topolnik

Vous pouvez utiliser Goyave .

Set<T> set = Sets.newHashSet(iterable);

ou pour le faire lire comme une phrase importation statique,

import static com.google.common.collect.Sets.*;

Set<T> set = newHashSet(iterable);
43
ConnorWGarvey

Bien sûr, cela est indiqué dans ceci réponse. En gros, parcourez l'itérable et copiez son contenu dans une collection:

public static <T> List<T> copyIterable(Iterable<T> iterable) {
    Iterator<T> iter = iterable.iterator();
    List<T> copy = new ArrayList<T>();
    while (iter.hasNext())
        copy.add(iter.next());
    return copy;
}

Utilisez-le comme suit: l'objet List résultant peut être transmis en tant que paramètre au constructeur HashSet.

Iterable<Integer> list = Arrays.asList(1, 2, 3);
List<Integer> copy = copyIterable(list);
Set<Integer> aSet = new HashSet<Integer>(copy);

EDIT

Je me suis toujours trompé. Iterable est une super-interface de Collection; une conversion simple (mais non sécurisée) fera l'affaire, à condition que Iterable soit au début un Collection.

Iterable<Integer> list = Arrays.asList(1, 2, 3);
Set<Integer> aSet = new HashSet<Integer>((Collection)list); // it works!
5
Óscar López

Ajoutez juste chacun.

public static <T> Set<T> setFromIterable(Iterable<T> i) {
    HashSet<T> set = new HashSet<T>();
    Iterator<T> it = i.iterator();
    while (it.hasNext()) {
        set.add(it.next());
    }
    return set;
}

Iterable<Integer> someIterable = ...;
Set<Integer> someSet = setFromIterable(someIterable);

Notez que vous not utilisez le constructeur new HashSet<Integer>(someIterator), car il n’existe pas. Appelez simplement la méthode statique.

3
wchargin

L'interface Iterable permet à la syntaxe "foreach" de fonctionner, la méthode la plus propre est donc probablement:

public <T> Set<T> toSet(Iterable<T> collection) {
    HashSet<T> set = new HashSet<T>();
    for (T item: collection)
        set.add(item);
    return set;
}
0
Don Roby