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?.
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(); }
}
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);
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!
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.
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;
}