23

我想用一个 Iterable 在 Java 中初始化一个集合实现(HashSet)。但是,HashSet 的构造函数不接受 Iterables,而只接受 Collections 类型的对象。

有没有办法从 Iterable 转换为 Collections 的某些子类型。

4

7 回答 7

51

你可以使用番石榴

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

或者让它读起来像一个句子静态导入,

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

Set<T> set = newHashSet(iterable);
于 2013-05-08T20:47:22.303 回答
7

HashSet构造函数不仅仅依赖于Iterable提供的东西:它想预先知道size集合的 ,以便优化地构造底层HashMap. 如果你有一个真正的、朴素Iterable的、不知道它的大小的,那么你必须通过多种明显的方式Iterable把它变成一个常规的来预先意识到它的存在。Collection

另一方面,如果您有一个更丰富的对象并且已经知道它的大小,那么创建一个将您包装Iterable到一个集合中的极简适配器类是值得的size,除了将调用转发到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(); }
}
于 2013-05-08T21:01:20.803 回答
6

当然,它显示在这个答案中。基本上,遍历可迭代对象并将其内容复制到集合中:

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;
}

如下使用它,生成的List对象可以作为参数传递给HashSet构造函数。

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

编辑

我一直都误会了。Iterable是 的超接口Collection,所以只要Iterable是 aCollection开头的简单(但不安全)强制转换就可以解决问题。

Iterable<Integer> list = Arrays.asList(1, 2, 3);
Set<Integer> aSet = new HashSet<Integer>((Collection)list); // it works!
于 2013-05-08T20:46:24.160 回答
3

只需添加每个。

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);

请注意,您使用构造函数new HashSet<Integer>(someIterator),因为它不存在。只需调用静态方法。

于 2013-05-08T20:45:47.117 回答
2

Iterable接口允许“ foreach”语法工作,所以最干净的方法可能是:

public <T> Set<T> toSet(Iterable<T> collection) {
    HashSet<T> set = new HashSet<T>();
    for (T item: collection)
        set.add(item);
    return set;
}
于 2013-05-08T20:54:01.043 回答
0

我使用这个单线(Java 8+),它只依赖于java.util.stream

StreamSupport.stream(myIterable, false).collect(Collectors.toSet());

// or with static imports:
stream(myIterable, false).collect(toSet());
于 2021-05-19T16:16:01.773 回答
-1

为了简洁起见,重复了一些答案。下面为我​​将 String 类型的 Iterable 转换为 Set(Java8) 工作。

Iterable<String> stringIterable = Arrays.asList("str1", "str2", "str3");
Set<String> stringHashSet = new HashSet<>((Collection<? extends String>) stringIterable);
于 2021-03-04T23:53:54.370 回答