【问题标题】:How to convert an Array to a Set in Java如何在 Java 中将数组转换为集合
【发布时间】:2011-03-05 02:42:45
【问题描述】:

我想在 Java 中将数组转换为 Set。有一些明显的方法可以做到这一点(即使用循环),但我想要一些更整洁的方法,比如:

java.util.Arrays.asList(Object[] a);

有什么想法吗?

【问题讨论】:

    标签: java collections arrays set


    【解决方案1】:

    在你执行Arrays.asList(array)之后你可以执行Set set = new HashSet(list);

    这是一个示例方法,你可以这样写:

    public <T> Set<T> GetSetFromArray(T[] array) {
        return new HashSet<T>(Arrays.asList(array));
    }
    

    【讨论】:

    • 我希望有一种方法可以直接从数组中返回一个集合,是否存在?
    • 你可以自己写,如果你这么热心的话:)
    【解决方案2】:

    像这样:

    Set<T> mySet = new HashSet<>(Arrays.asList(someArray));
    

    在 Java 9+ 中,如果不可修改的集合是可以的:

    Set<T> mySet = Set.of(someArray);
    

    在 Java 10+ 中,泛型类型参数可以从数组组件类型中推断出来:

    var mySet = Set.of(someArray);
    

    小心

    Set.of 抛出 IllegalArgumentException - 如果有任何重复 someArray 中的元素。 查看更多详情:https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Set.html#of(E...)

    【讨论】:

    • 我会省略最后一个 ,否则很好的 oneliner!
    • @dataoz:错误; Arrays.asList 是 O(1)。
    • 请注意,如果您在 int[] 等基元数组上使用此方法,它将返回 List,因此您应该使用包装类来获得预期的行为。
    • @AjayGautam:那只是在番石榴中。
    • 我每次都会(几乎)将可读性置于效率之上:blog.codinghorror.com/…
    【解决方案3】:

    new HashSet&lt;Object&gt;(Arrays.asList(Object[] a));

    但我认为这样会更有效率:

    final Set s = new HashSet<Object>();    
    for (Object o : a) { s.add(o); }         
    

    【讨论】:

    • 那真的不会更有效(至少不值得考虑)。
    • 在构造函数版本中,HashSet的初始容量是根据数组的大小来设置的,例如
    • 这个答案并不像看起来那么愚蠢:'Collections.addAll(mySet, myArray);'从 java.util.Collections 使用相同的迭代器,但加上一个布尔运算。另外,正如 Bert F 指出的那样,Collections.addAll“在大多数实现下可能运行得更快”比 c.addAll(Arrays.asList(elements))
    【解决方案4】:

    使用Guava,您可以:

    T[] array = ...
    Set<T> set = Sets.newHashSet(array);
    

    【讨论】:

    • 还有 ImmutableSet.copyOf(array)。 (我想我也想指出。)
    • 对于可以使用的固定元素列表:ImmutableSet.of(e1, e2, ..., en)。请注意,您将无法在创建后更改此 Set。
    • 请注意,Guava javadoc 说:“这种方法实际上不是很有用,将来可能会被弃用。”他们指向标准new HashSet&lt;T&gt;(Arrays.asList(someArray))。见google.github.io/guava/releases/19.0/api/docs/com/google/common/…
    【解决方案5】:
    Set<T> mySet = new HashSet<T>();
    Collections.addAll(mySet, myArray);
    

    这是来自 JDK 6 的 Collections.addAll(java.util.Collection, T...)

    另外:如果我们的数组充满了原语怎么办?

    对于 for 循环即可一次性完成包装和添加设置。

    对于 JDK >= 8,一个有吸引力的选项是:

    Arrays.stream(intArray).boxed().collect(Collectors.toSet());
    

    【讨论】:

    • 您可以使用java.util.Collections.addAll 做到这一点。另外,我不会再推荐 Commons Collections,因为它没有被泛化并且 Guava 存在。
    • +1 比 SLaks 的答案更有效率,即使它不是单行的。
    • @Adrian 我对此表示怀疑。我认为addAll 将是 O(n)。
    • 我相信 Adrian 的观点是关于 SLaks 的解决方案如何创建一个最终被丢弃的 List 实例。这种差异的实际影响可能非常小,但可能取决于您执行此操作的上下文 - 紧密循环或非常大的集合可能表现得非常不同在这两个选项之间。
    • 根据 Collections.addAll() javadoc (Java 6):“这种便捷方法的行为与 c.addAll(Arrays.asList(elements)) 的行为相同,但这种方法很可能在大多数实现下运行得更快。”
    【解决方案6】:

    快点:你可以做到:

    // Fixed-size list
    List list = Arrays.asList(array);
    
    // Growable list
    list = new LinkedList(Arrays.asList(array));
    
    // Duplicate elements are discarded
    Set set = new HashSet(Arrays.asList(array));
    

    倒转

    // Create an array containing the elements in a list
    Object[] objectArray = list.toArray();
    MyClass[] array = (MyClass[])list.toArray(new MyClass[list.size()]);
    
    // Create an array containing the elements in a set
    objectArray = set.toArray();
    array = (MyClass[])set.toArray(new MyClass[set.size()]);
    

    【讨论】:

      【解决方案7】:

      有时使用一些标准库会有很大帮助。尝试查看Apache Commons Collections。在这种情况下,您的问题只是简单地转化为这样的事情

      String[] keys = {"blah", "blahblah"}
      Set<String> myEmptySet = new HashSet<String>();
      CollectionUtils.addAll(pythonKeywordSet, keys);
      

      这里是CollectionsUtils javadoc

      【讨论】:

      • 用户可能不会使用 apache commons
      • 如果用户不使用apache commons,那是他的第一个错误。
      • 你为什么要用这个而不是java.util.Collections.addAll(myEmptySet, keys);??
      【解决方案8】:

      Eclipse Collections 中,以下将起作用:

      Set<Integer> set1 = Sets.mutable.of(1, 2, 3, 4, 5);
      Set<Integer> set2 = Sets.mutable.of(new Integer[]{1, 2, 3, 4, 5});
      MutableSet<Integer> mutableSet = Sets.mutable.of(1, 2, 3, 4, 5);
      ImmutableSet<Integer> immutableSet = Sets.immutable.of(1, 2, 3, 4, 5);
      
      Set<Integer> unmodifiableSet = Sets.mutable.of(1, 2, 3, 4, 5).asUnmodifiable();
      Set<Integer> synchronizedSet = Sets.mutable.of(1, 2, 3, 4, 5).asSynchronized();
      ImmutableSet<Integer> immutableSet = Sets.mutable.of(1, 2, 3, 4, 5).toImmutable();
      

      注意:我是 Eclipse Collections 的提交者

      【讨论】:

        【解决方案9】:

        Java 8:

        String[] strArray = {"eins", "zwei", "drei", "vier"};
        
        Set<String> strSet = Arrays.stream(strArray).collect(Collectors.toSet());
        System.out.println(strSet);
        // [eins, vier, zwei, drei]
        

        【讨论】:

        • 是否值得并行执行?
        • @RaffiKhatchadourian 这不一定是并行完成的。 Arrays.stream 不对流做出任何承诺。为此,您必须在结果流上调用 parallel()。
        • 你也可以调用parallelStream()。回答@RaffiKhatchadourian 的问题,可能不是。如果您发现任何性能问题,请尝试衡量。
        • 一般情况下,避免并行。默认情况下,它在您的应用程序中使用单个线程池,启动线程和连接的开销比顺序流式传输数百个项目更糟糕。只有在极少数情况下,并行才能真正带来好处。
        【解决方案10】:

        Java 8

        我们也可以选择使用Stream。我们可以通过多种方式获取流:

        Set<String> set = Stream.of("A", "B", "C", "D").collect(Collectors.toCollection(HashSet::new));
        System.out.println(set);
        
        String[] stringArray = {"A", "B", "C", "D"};
        Set<String> strSet1 = Arrays.stream(stringArray).collect(Collectors.toSet());
        System.out.println(strSet1);
        
        // if you need HashSet then use below option.
        Set<String> strSet2 = Arrays.stream(stringArray).collect(Collectors.toCollection(HashSet::new));
        System.out.println(strSet2);
        

        Collectors.toSet() 的源代码显示元素是一个一个地添加到HashSet,但规范不保证它将是HashSet

        “类型、可变性、可序列化性或 返回的 Set 的线程安全性。”

        所以最好使用后面的选项。输出是: [A, B, C, D] [A, B, C, D] [A, B, C, D]

        不可变集 (Java 9)

        Java 9 引入了Set.of 静态工厂方法,它为提供的元素或数组返回不可变集合。

        @SafeVarargs
        static <E> Set<E> of​(E... elements)
        

        查看Immutable Set Static Factory Methods了解详情。

        不可变集 (Java 10)

        我们还可以通过两种方式获得不可变集合:

        1. Set.copyOf(Arrays.asList(array))
        2. Arrays.stream(array).collect(Collectors.toUnmodifiableList());

        Collectors.toUnmodifiableList() 方法在内部使用了 Java 9 中引入的Set.of。更多信息请查看我的answer

        【讨论】:

        • +1 for Stream.of() - 我不知道那个。关于Collectors.toSet() 的一个小问题:你说规范不保证一个一个地添加元素,但这就是它的意思:“积累......到一个新的Set”。而且它更具可读性 - 如果您不需要具体类型、可变性、可序列化和线程安全性的保证,那么对我来说更可取。
        • @AndrewSpencer Spec 不保证集合实现将是HashSet。它只保证它将是Set,这就是我的意思。希望我澄清了。
        • 抱歉,谢谢,我将其误读为“规范不保证逐一添加”而不是“规范不保证 HashSet”。建议进行编辑以澄清。
        【解决方案11】:

        可变参数也可以!

        Stream.of(T... values).collect(Collectors.toSet());
        

        【讨论】:

        • 比 2-3 衬里更好。
        【解决方案12】:
        Set<T> b = new HashSet<>(Arrays.asList(requiredArray));
        

        【讨论】:

        【解决方案13】:

        我已经根据上面的建议写了下面的内容 - 偷它......这很好!

        /**
         * Handy conversion to set
         */
        public class SetUtil {
            /**
             * Convert some items to a set
             * @param items items
             * @param <T> works on any type
             * @return a hash set of the input items
             */
            public static <T> Set<T> asSet(T ... items) {
                return Stream.of(items).collect(Collectors.toSet());
            }
        }
        

        【讨论】:

        • Arrays.stream 可能比 Stream.of 更好。
        【解决方案14】:
        private Map<Integer, Set<Integer>> nobreaks = new HashMap();
        nobreaks.put(1, new HashSet(Arrays.asList(new int[]{2, 4, 5})));
        System.out.println("expected size is 3: " +nobreaks.get(1).size());
        

        输出是

        expected size is 3: 1
        

        改成

        nobreaks.put(1, new HashSet(Arrays.asList( 2, 4, 5 )));
        

        输出是

        expected size is 3: 3
        

        【讨论】:

          【解决方案15】:

          Java 10 中:

          String[] strs = {"A", "B"};
          Set<String> set = Set.copyOf(Arrays.asList(strs));
          

          Set.copyOf 返回一个不可修改的Set,其中包含给定Collection 的元素。

           给定的Collection 不得为null,且不得包含任何null 元素。

          【讨论】:

            【解决方案16】:

            使用CollectionUtilsArrayUtils 来自stanford-postagger-3.0.jar

            import static edu.stanford.nlp.util.ArrayUtils.asSet;
            or 
            import static edu.stanford.nlp.util.CollectionUtils.asSet;
            
              ...
            String [] array = {"1", "q"};
            Set<String> trackIds = asSet(array);
            

            【讨论】:

              【解决方案17】:

              已经有很多很好的答案,但其中大多数不适用于基元数组(如int[]long[]char[]byte[] 等)

              在 Java 8 及更高版本中,您可以将数组装箱:

              Integer[] boxedArr = Arrays.stream(arr).boxed().toArray(Integer[]::new);
              

              然后转换成使用流设置:

              Stream.of(boxedArr).collect(Collectors.toSet());
              

              【讨论】:

                【解决方案18】:

                对于任何解决 Android 问题的人:

                Kotlin 集合解决方案

                星号*spread 运算符。它单独应用集合中的所有元素,每个元素都按顺序传递给vararg 方法参数。相当于:

                val myArray = arrayOf("data", "foo")
                val mySet = setOf(*myArray)
                
                // Equivalent to
                val mySet = setOf("data", "foo")
                
                // Multiple spreads ["data", "foo", "bar", "data", "foo"]
                val mySet = setOf(*myArray, "bar", *myArray)
                

                不传递参数setOf() 会导致一个空集。

                除了setOf,您还可以将其中任何一个用于特定的哈希类型:

                hashSetOf()
                linkedSetOf()
                mutableSetOf()
                sortableSetOf()
                

                这是明确定义集合项类型的方法。

                setOf<String>()
                hashSetOf<MyClass>()
                

                【讨论】:

                  【解决方案19】:

                  如果您需要构建一个内部只有一个元素的不可变集合,您可以使用Collections.singleton(...)。这是一个例子:

                  Set<String> mySet = Collections.singleton("Have a good day :-)");
                  

                  这不能回答最初的问题,但可能对某人有用(至少对我来说)。如果您认为此答案不合适,请告诉我,我将删除它。

                  【讨论】:

                    猜你喜欢
                    • 2015-07-31
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-12-02
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多