169

我有一个基元数组,例如 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>

还要检查 为什么数组不能分配给 Iterable? 在回答之前。

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

最后,由于似乎有一个家庭作业,请避免发布家庭作业代码。

4

10 回答 10

136
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 的回答启发)

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();
于 2012-04-26T14:40:26.803 回答
49

只是我的 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.");
            }
        };
    }
};
于 2013-01-10T00:20:12.103 回答
35

使用 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();
于 2015-11-16T16:07:20.427 回答
20

Guava 以Int.asList()的形式提供您想要的适配器。关联类中的每个原始类型都有一个等价物,例如Booleansforboolean等。

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<int[]>而不是Iterator<Integer>. 发生的情况是,您创建了一个包含数组的 1 元素数组列表,而不是创建一个由数组支持的列表。

于 2013-01-11T04:18:53.850 回答
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
于 2019-09-14T02:47:31.740 回答
8

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

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

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

于 2013-03-27T14:12:57.473 回答
4

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

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

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

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

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

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

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

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

于 2015-04-29T17:54:43.167 回答
4

您可以IterableOfCactoos使用:

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"
);
于 2017-06-19T09:00:33.290 回答
1

虽然已经发布了类似的答案,但我认为使用新 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

于 2018-05-02T15:24:02.180 回答
-2

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

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

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

于 2017-04-29T15:08:36.333 回答