【问题标题】:Initializing a Set with an Iterable使用 Iterable 初始化 Set
【发布时间】:2013-05-03 05:23:48
【问题描述】:

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

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

【问题讨论】:

  • 我认为问题本身已经足够不同(因为一个是有序集合),或者另一个问题不够笼统,无法同时支持有序和无序。
  • 好吧,链接副本通过提供“一种从 Iterable 转换为 Collection 的某些子类型的方法”来回答所提出的字面问题。但是,我同意这(构造一个临时的ArrayList)不一定是从Iterable 初始化HashSet 的最佳方式。
  • 如果你在类路径上有 Spring Data,你可以使用Streamable.of(iterable).toSet()。如果 Spring Data 恰好是 Iterable 的来源,您还有更多选择:stackoverflow.com/a/67413334/66686

标签: java set iterable


【解决方案1】:

您可以使用Guava

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

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

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

Set<T> set = newHashSet(iterable);

【讨论】:

    【解决方案2】:

    HashSet 构造函数不仅仅依赖于Iterable 提供的功能:它想预先知道集合的size,以便优化构造底层HashMap。如果你有一个真正的、朴素的Iterable,它不知道它的大小,那么你必须通过多种明显的方式将它变成一个普通的Collection,预先实现Iterable

    另一方面,如果您有一个已经知道其大小的更丰富的对象,那么创建一个将您的 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(); }
    }
    

    【讨论】:

    • 很好的解释。我想我明白你的观点和直觉。
    【解决方案3】:

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

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

    编辑

    我一直都错了。 IterableCollection 的超接口,所以只要 IterableCollection 开始,一个简单(但不安全)的转换就可以解决问题。

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

    【讨论】:

    • 我避免显式迭代 Iterable 或自己使用 Iterator。我正在寻找一种机制,以便 HashSet 的构造函数或任何 Set 实现都可以接受它。 (顺便说一句:我没有对你投反对票)。但如果你能告诉我一个解决方法,我肯定会支持你。 :-)
    • 我在我的 Netbeans 上得到了这个。 no suitable constructor found for HashSet(Iterator&lt;Integer&gt;)
    • @WChargin 已修复,谢谢。请重新考虑否决票。
    • CollectionIterable,但Iterable 不一定是Collection。因此,如果具体的 Iterable 不是 Collection,您的演员表是不安全的(如您所说)并且可能在运行时失败。
    • 将 Iterable 转换为 Collection 是个坏主意
    【解决方案4】:

    只需添加一个。

    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&lt;Integer&gt;(someIterator),因为它不存在。只需调用静态方法即可。

    【讨论】:

    • 我认为您混淆了IterableIterator
    • 是的,你是对的。但即使 iterator() 也不起作用。我拥有的对象也返回了一个 Iterator(),但即使这样也是构造函数不能接受的。
    • 柯克:你说得对;谢谢。 @Vaid 请看我的编辑。
    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

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

      StreamSupport.stream(myIterable, false).collect(Collectors.toSet());
      
      // or with static imports:
      stream(myIterable, false).collect(toSet());
      

      【讨论】:

        【解决方案7】:

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

        Iterable<String> stringIterable = Arrays.asList("str1", "str2", "str3");
        Set<String> stringHashSet = new HashSet<>((Collection<? extends String>) stringIterable);
        

        【讨论】:

        • 这仅适用于Collection,如果您已经知道您有更具体的内容,那么您应该正确输入。
        猜你喜欢
        • 2013-06-26
        • 1970-01-01
        • 1970-01-01
        • 2012-06-16
        • 1970-01-01
        • 2010-09-20
        • 1970-01-01
        • 1970-01-01
        • 2013-09-12
        相关资源
        最近更新 更多