【问题标题】:Convert Java Array to Iterable将 Java 数组转换为可迭代
【发布时间】:2012-05-07 07:38:04
【问题描述】:

我有一个基元数组,例如 int, int[] foo。它可能是小型的,也可能不是。

int foo[] = {1,2,3,4,5,6,7,8,9,0};

从中创建Iterable<Integer> 的最佳方法是什么?

Iterable<Integer> fooBar = convert(foo);

注意事项:

请不要使用循环来回答(除非你能很好地解释编译器如何对它们进行智能处理?)

还要注意

int a[] = {1,2,3};
List<Integer> l = Arrays.asList(a);

甚至不会编译

Type mismatch: cannot convert from List<int[]> to List<Integer>

同时检查 Why is an array not assignable to Iterable? 在回答之前。

另外,如果您使用某些库(例如 Guava),请解释为什么这是最好的。 (因为它来自谷歌不是一个完整的答案:P)

最后,由于似乎有关于这方面的作业,请避免发布作业代码。

【问题讨论】:

  • Iterator for array的可能重复
  • 将它们添加到 LinkedList,然后返回该 Set 的迭代器。

标签: java arrays iterable


【解决方案1】:
Integer foo[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

List<Integer> list = Arrays.asList(foo);
// or
Iterable<Integer> iterable = Arrays.asList(foo);

虽然您需要使用 Integer 数组(而不是 int 数组)才能使其工作。

对于原语,你可以使用番石榴:

Iterable<Integer> fooBar = Ints.asList(foo);
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>15.0</version>
    <type>jar</type>
</dependency>

对于带有 lambdas 的 Java8:(灵感来自 Jin Kwon's answer

final int[] arr = { 1, 2, 3 };
final Iterable<Integer> i1 = () -> Arrays.stream(arr).iterator();
final Iterable<Integer> i2 = () -> IntStream.of(arr).iterator();
final Iterable<Integer> i3 = () -> IntStream.of(arr).boxed().iterator();

【讨论】:

  • 两个注意事项:1)他有int,而不是Integer 2)List 已经是Iterable,所以第三行毫无意义。
  • 他需要Iterable,为什么会有第三行。
  • 第二行和第三行是我想说的选项:)
  • 这不是家庭作业的一部分,我只是想避免重复处理数组或列表内容的调试函数的代码......在环顾四周时,我确实找到了 Arrays.asList( ..);,但至少 Eclipse 似乎认为它不会做我想要的(例如,它将 Arrays.asList(foo) 的结果推断为 List,而不是 List... )我发现这个问题很有趣......(-在部分原因中破坏评论-)
  • 一般来说,人们可以想出很多方法来做到这一点,但我想知道什么是最好的(例如,与...相比,循环会慢得多……{好吧,问题是我什么都想不出来!:) }) 另外检查stackoverflow.com/questions/1160081/… 讨论为什么,我的问题不是为什么,而是如何,以及什么类型的容器最好(为什么是 ArrayList?事实上,我可以想象一些使用泛型的 AbstractList 包装器..,可能取决于大小...)
【解决方案2】:

只有我的 2 美分:

final int a[] = {1,2,3};

java.lang.Iterable<Integer> aIterable=new Iterable<Integer>() {

    public Iterator<Integer> iterator() {
       return new Iterator<Integer>() {
            private int pos=0;

            public boolean hasNext() {
               return a.length>pos;
            }

            public Integer next() {
               return a[pos++];
            }

            public void remove() {
                throw new UnsupportedOperationException("Cannot remove an element of an array.");
            }
        };
    }
};

【讨论】:

  • remove() 在 java 8 中不是必需的,因为它是抛出 UnsupportedOperationException 的默认方法。仅当您想提供更好的解释信息时。
  • +1 我做了类似的事情来从String 创建一个Iterator&lt;Character&gt;。实现自己的Iterator 似乎是避免不必要地遍历所有值以从对象类型转换为原始类型的唯一方法(例如通过 Guava 的Ints.asList()),只是为了能够获得Iterator来自创建的List
  • 你说得对,亚历克斯。 Java 8 添加了默认方法。2013 年,我在这里添加了这段古老的代码。
【解决方案3】:

Guava 提供你想要的适配器Int.asList()。关联类中的每个原始类型都有一个等价物,例如,Booleans 对应于 boolean 等。

int foo[] = {1,2,3,4,5,6,7,8,9,0};
Iterable<Integer> fooBar = Ints.asList(foo);
for(Integer i : fooBar) {
    System.out.println(i);
}

上面使用Arrays.asList 的建议将不起作用,即使它们可以编译,因为您得到的是Iterator&lt;int[]&gt; 而不是Iterator&lt;Integer&gt;。发生的情况是,您创建了一个包含数组的 1 元素数组列表,而不是创建一个由数组支持的列表。

【讨论】:

【解决方案4】:

我遇到了同样的问题并这样解决了:

final YourType[] yourArray = ...;
return new Iterable<YourType>() {
  public Iterator<YourType> iterator() {
     return Iterators.forArray(yourArray);   // Iterators is a Google guava utility
  }
}

迭代器本身是一个懒惰的UnmodifiableIterator,但这正是我所需要的。

【讨论】:

    【解决方案5】:

    首先,我只能同意Arrays.asList(T...) 显然是包装器类型或具有非原始数据类型的数组的最佳解决方案。此方法调用 Arrays 类中的简单私有静态 AbstractList 实现的构造函数,它基本上将给定的数组引用保存为字段并通过覆盖所需的方法来模拟列表。

    如果您可以为数组选择原始类型或 Wrapper 类型,我会在这种情况下使用 Wrapper 类型,但当然,它并不总是有用或必需的。 您可以做的只有两种可能性:

    1)您可以为每个原始数据类型数组创建一个具有静态方法的类(boolean, byte, short, int, long, char, float, double 返回一个Iterable&lt;WrapperType&gt;。这些方法将使用Iterator(除了Iterable)的匿名类,这些类允许包含包含方法的参数的引用(例如 int[])作为字段以实现方法。

    ->这种方法是高效的并且可以节省内存(除了新创建的方法,即使使用 Arrays.asList() 会以同样的方式占用内存)

    2)由于数组没有方法(在您链接的一侧阅读),它们也无法提供Iterator 实例。如果你真的懒得写新类,你必须使用一个已经存在的类的实例来实现Iterable,因为除了实例化Iterable或子类型之外别无他法。
    创建实现 Iterable 的现有 Collection 派生的唯一方法是使用循环(除非您使用上述匿名类)或实例化一个 Iterable 实现类,其构造函数允许原始类型数组(因为 Object[] 不'不允许带有原始类型元素的数组),但据我所知,Java API 没有这样的类。

    循环的原因可以很容易地解释:
    对于每个集合你需要对象和原始数据类型不是对象。对象比原始类型大得多,因此它们需要额外的数据,这些数据必须为原始类型数组的每个元素生成。这意味着如果三种方式的两种方式(使用Arrays.asList(T...) 或使用现有的集合)需要对象的聚合,则需要为int[] 数组的每个原始值创建包装器对象。第三种方法将按原样使用数组并在匿名类中使用它,因为我认为由于性能快,它更可取。

    还有第三种策略使用Object 作为要使用数组或Iterable 的方法的参数,它需要类型检查以确定参数的类型,但我不推荐它在就像您通常需要考虑的那样,Object 并不总是需要的类型,并且在某些情况下您需要单独的代码。

    总之,这是 Java 有问题的通用类型系统的错误,它不允许使用原始类型作为通用类型,这将通过简单地使用 Arrays.asList(T...) 来节省大量代码。所以你需要为每个原始类型数组编程,你需要这样一个方法(这对 C++ 程序使用的内存基本上没有区别,它会为每个使用的类型参数创建一个单独的方法。

    【讨论】:

      【解决方案6】:

      使用 Java 8,您可以做到这一点。

      final int[] arr = {1, 2, 3};
      final PrimitiveIterator.OfInt i1 = Arrays.stream(arr).iterator();
      final PrimitiveIterator.OfInt i2 = IntStream.of(arr).iterator();
      final Iterator<Integer> i3 = IntStream.of(arr).boxed().iterator();
      

      【讨论】:

        【解决方案7】:

        在 java8 中,IntSteam 流可以装箱为整数流。

        public static Iterable<Integer> toIterable(int[] ints) {
            return IntStream.of(ints).boxed().collect(Collectors.toList());
        }
        

        我认为性能取决于数组的大小。

        【讨论】:

          【解决方案8】:

          您可以从Cactoos 使用IterableOf

          Iterable<String> names = new IterableOf<>(
            "Scott Fitzgerald", "Fyodor Dostoyevsky"
          );
          

          然后,您可以使用ListOf 将其转换为列表:

          List<String> names = new ListOf<>(
            new IterableOf<>(
              "Scott Fitzgerald", "Fyodor Dostoyevsky"
            )
          );
          

          或者简单地说:

          List<String> names = new ListOf<>(
            "Scott Fitzgerald", "Fyodor Dostoyevsky"
          );
          

          【讨论】:

            【解决方案9】:

            虽然已经发布了类似的答案,但我认为使用新 PrimitiveIterator.OfInt 的原因尚不清楚。一个好的解决方案是使用 Java 8 PrimitiveIterator,因为它专门用于原始 int 类型(并且避免了额外的装箱/拆箱惩罚):

                int[] arr = {1,2,3};
                // If you use Iterator<Integer> here as type then you can't get the actual benefit of being able to use nextInt() later
                PrimitiveIterator.OfInt iterator = Arrays.stream(arr).iterator();
                while (iterator.hasNext()) {
                    System.out.println(iterator.nextInt());
                    // Use nextInt() instead of next() here to avoid extra boxing penalty
                }
            

            参考:https://doc.bccnsoft.com/docs/jdk8u12-docs/api/java/util/PrimitiveIterator.OfInt.html

            【讨论】:

              【解决方案10】:

              在 Java 8 或更高版本中,Iterable 是一个函数接口,返回 Iterator。 所以你可以这样做。

              static Iterable<Integer> convert(int[] array) {
                  return () -> Arrays.stream(array).iterator();
              }
              

              int[] array = {1, 2, 3};
              Iterable<Integer> iterable = convert(array);
              for (int i : iterable)
                  System.out.println(i);
              

              输出:

              1
              2
              3
              

              【讨论】:

                猜你喜欢
                • 2021-04-21
                • 2015-02-21
                • 2021-08-26
                • 2019-06-20
                • 2016-12-13
                • 2018-07-13
                • 2015-12-22
                • 1970-01-01
                • 2018-05-12
                相关资源
                最近更新 更多