转换 Java 数组到 Iterable

我有一个基元数组,例如 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? 在回答之前。

此外,如果你使用一些库(例如,番石榴) ,请解释为什么这是最好的。(因为它来自谷歌并不是一个完整的答案: P)

最后,因为似乎有一个关于这方面的家庭作业,避免发布家庭作业代码。

202542 次浏览
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();

我只想说:

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.");
}
};
}
};

番石榴提供了所需的适配器 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<int[]>而不是 Iterator<Integer>。实际发生的情况是,您没有创建一个由数组支持的列表,而是创建了一个由1个元素组成的数组列表,其中包含数组。

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

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

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

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

如果您可以为数组选择基元类型还是 Wrapper 类型,那么在这种情况下我会使用 Wrapper 类型,但是当然,它并不总是有用或必需的。 只有两种可能性: < br > < br > 1)您可以为每个基元数据类型数组(boolean, byte, short, int, long, char, float, double返回 Iterable<WrapperType>)创建一个具有静态方法的类。这些方法将使用 Iterator的匿名类(除了 Iterable) ,这些类允许包含组合方法的参数的引用(例如 int[])作为字段,以便实现这些方法。

- > 这种方法是性能和节省您的内存(除了内存的新创建的方法,即使,使用 Arrays.asList()将采取相同的方式内存)

2)由于数组没有方法(在你链接的那一边读取) ,它们也不能提供 Iterator实例。如果您确实懒得编写新类,那么必须使用实现 Iterable的现有类的实例,因为除了实例化 Iterable或子类型之外,没有其他办法。
创建现有的实现 Iterable的 Collection 派生物的唯一方法是使用一个循环(除非你使用上面描述的匿名类)或者实例化一个 Iterable实现类,它的构造函数允许一个原始类型数组(因为 Object[]不允许带有原始类型元素的数组) ,但是据我所知,Java API 没有这样的类。< br > < br > 循环的原因很容易解释: 对于每个 Collection,您都需要 Object,而基本数据类型不是对象。对象比基元类型大得多,因此它们需要额外的数据,这些数据必须为基元类型数组的每个元素生成。这意味着如果三种方法中的两种(使用 Arrays.asList(T...)或使用现有 Collection)需要对象的聚合,则需要为 int[]数组的每个基元值创建包装器对象。第三种方法是按原样使用数组,并在匿名类中使用它,因为我认为由于性能快,这种方法更可取。

还有第三种策略,使用 Object作为方法的参数,你想使用数组或者 Iterable,它需要类型检查来找出参数的类型,但是我不推荐这样做,因为你通常需要考虑对象并不总是所需的类型,在某些情况下你需要单独的代码。< br > < br > 总之,这是 Java 有问题的泛型类型系统的错误,它不允许使用原始类型作为泛型类型,这将节省大量的代码通过使用简单的 Arrays.asList(T...)。因此,您需要为每个基元类型数组编程,您需要这样一个方法(它基本上与 C + + 程序使用的内存没有区别,C + + 程序将为每个使用的类型参数创建一个单独的方法。

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

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

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

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

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

你可以从 仙人掌使用 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"
);

虽然类似的答案已经发布了一些,但是我认为使用新的 PrimitiveIterator.OfInt 的原因并不清楚。一个好的解决方案是使用 Java8 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

在 Java8或更高版本中,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