I want to initialize a Set Implementation (HashSet) in Java with an Iterable. However, the constructor of HashSet doesn't accept Iterables, but only Collections type objects.
Is there a way to convert from Iterable to some subtype of Collections.
I want to initialize a Set Implementation (HashSet) in Java with an Iterable. However, the constructor of HashSet doesn't accept Iterables, but only Collections type objects.
Is there a way to convert from Iterable to some subtype of Collections.
HashSet
constructor relies on more than what Iterable
offers: it wants to know the size
of the collection up front in order to optimally construct the underlying HashMap
. If you have a true, austere Iterable
, which doesn't know its size, then you'll have to realize the Iterable
up front by turning it into a regular Collection
in any of a number of obvious ways.
If, on the other hand, you have a richer object that already knows its size, then it would pay to create a minimalist adapter class that wraps your Iterable
into a collection, implementing just size
in addition to forwarding the call to 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(); }
}
You can use Guava.
Set<T> set = Sets.newHashSet(iterable);
or to make it read like a sentence static import,
import static com.google.common.collect.Sets.*;
Set<T> set = newHashSet(iterable);
HashSet
constructor relies on more than what Iterable
offers: it wants to know the size
of the collection up front in order to optimally construct the underlying HashMap
. If you have a true, austere Iterable
, which doesn't know its size, then you'll have to realize the Iterable
up front by turning it into a regular Collection
in any of a number of obvious ways.
If, on the other hand, you have a richer object that already knows its size, then it would pay to create a minimalist adapter class that wraps your Iterable
into a collection, implementing just size
in addition to forwarding the call to 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(); }
}
Sure, it's shown in this answer. Basically, iterate over the iterable and copy its contents in a 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;
}
Use it as follows, the resulting List
object can be passed as a parameter to the HashSet
constructor.
Iterable<Integer> list = Arrays.asList(1, 2, 3);
List<Integer> copy = copyIterable(list);
Set<Integer> aSet = new HashSet<Integer>(copy);
EDIT
I've been mistaken all along. Iterable
is a superinterface of Collection
, so a simple (but unsafe) cast will do the trick, as long as the Iterable
was a Collection
to begin with.
Iterable<Integer> list = Arrays.asList(1, 2, 3);
Set<Integer> aSet = new HashSet<Integer>((Collection)list); // it works!
no suitable constructor found for HashSet(Iterator<Integer>)
–
Tunisia Collection
is an Iterable
, but an Iterable
is not necessarily a Collection
. So, your cast is unsafe (as you stated) and could fail at runtime if the concrete Iterable
was not also a Collection
. –
Swedenborgianism Collection
. You should have mentioned this from the beginning! –
Uralic The Iterable interface allows the "foreach" syntax to work, so the cleanest way is likely:
public <T> Set<T> toSet(Iterable<T> collection) {
HashSet<T> set = new HashSet<T>();
for (T item: collection)
set.add(item);
return set;
}
Just add each one.
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);
Note that you don't use the constructor new HashSet<Integer>(someIterator)
, because that doesn't exist. Just call the static method.
Iterable
and Iterator
. –
Rootless I use this one-liner (with Java 8+), which only relies on java.util.stream
:
StreamSupport.stream(myIterable.spliterator(), false).collect(Collectors.toSet());
// or with static imports:
stream(myIterable.spliterator(), false).collect(toSet());
Putting somewhat a repeated answer for conciseness. Below worked for me for converting the Iterable of String type to a Set(Java8).
Iterable<String> stringIterable = Arrays.asList("str1", "str2", "str3");
Set<String> stringHashSet = new HashSet<>((Collection<? extends String>) stringIterable);
Collection
, and if you already know that you have something more specific then you should type it correctly. –
Rebhun © 2022 - 2024 — McMap. All rights reserved.
ArrayList
) is not necessarily the best way to intialize aHashSet
from anIterable
. – HistoneStreamable.of(iterable).toSet()
. If Spring Data happens to be the source of theIterable
you have even more options: https://mcmap.net/q/74121/-easy-way-to-convert-iterable-to-collection – Hautegaronne