我有一个基元数组,例如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? 在回答之前。
另外,如果你使用一些库(例如,番石榴),请解释为什么这是最好的。 (因为它来自谷歌并不是一个完整的答案:P)
最后,因为似乎有关于此的功课,所以请避免发布家庭作业代码。
答案 0 :(得分:103)
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
数组)才能实现此目的。
对于原语,您可以使用guava:
Iterable<Integer> fooBar = Ints.asList(foo);
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>15.0</version>
<type>jar</type>
</dependency>
对于Java8 :(来自Jin Kwon的回答)
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();
答案 1 :(得分:40)
只是我的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.");
}
};
}
};
答案 2 :(得分:26)
使用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();
答案 3 :(得分:20)
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<int[]>
而不是Iterator<Integer>
而进行编译。发生的是,您创建了一个包含数组的1元素数组列表,而不是创建由数组支持的列表。
答案 4 :(得分:8)
我遇到了同样的问题并解决了这个问题:
final YourType[] yourArray = ...;
return new Iterable<YourType>() {
public Iterator<YourType> iterator() {
return Iterators.forArray(yourArray); // Iterators is a Google guava utility
}
}
迭代器本身是一个懒惰的UnmodifiableIterator
,但这正是我所需要的。
答案 5 :(得分:3)
首先,我只能同意Arrays.asList(T...)
显然是Wrapper类型或具有非原始数据类型的数组的最佳解决方案。此方法在AbstractList
类中调用一个简单的私有静态Arrays
实现的构造函数,它基本上将给定的数组引用保存为字段,并通过覆盖所需的方法来模拟列表。
如果您可以为阵列选择原始类型或Wrapper类型,我会在这种情况下使用Wrapper类型,但当然,它并不总是有用或必需。
您只能有两种可能性:
1)您可以为每个原始数据类型数组创建一个带有静态方法的类(boolean, byte, short, int, long, char, float, double
返回Iterable<
WrapperType >
。这些方法将使用Iterator
的匿名类(除此之外) Iterable
)允许包含包含方法的参数的引用(例如int[]
)作为字段以实现方法。
- &GT;这种方法具有高效性,可以节省内存(除了新创建的方法的内存,即使使用Arrays.asList()
会以相同的方式记忆)
2)由于数组没有方法(在你链接的一边阅读),他们也不能提供Iterator
实例。如果你真的懒得编写新类,你必须使用已经存在的实现Iterable
的类的实例,因为除了实例化Iterable
或子类型之外别无他法。
创建实现Iterable
的现有Collection衍生物的唯一方法是使用循环(除了您使用上面描述的匿名类)或者实例化一个Iterable
实现类,其构造函数允许一个原始类型数组(因为Object[]
不允许使用基本类型元素的数组)但据我所知,Java API没有类似这样的类。
原因循环可以很容易地解释:
对于你需要的每个集合对象和原始数据类型不是对象。对象比原始类型大得多,因此它们需要为基本类型数组的每个元素生成必须生成的附加数据。这意味着如果两种方式(使用Arrays.asList(T...)
或使用现有Collection)需要聚合对象,则需要为包含对象的int[]
数组的每个原始值创建。第三种方式是按原样使用数组,并在匿名类中使用它,因为我认为它更好,因为性能快。
还有第三种策略使用Object
作为要使用数组或Iterable
的方法的参数,并且需要进行类型检查以确定参数具有哪种类型,但是我不会# 39;因为您通常需要考虑对象并不总是所需的类型,并且在某些情况下需要单独的代码,因此根本不推荐它。
总之,它是Java有问题的通用类型系统的错误,它不允许使用原始类型作为通用类型,通过简单地使用Arrays.asList(T...)
来节省大量代码。所以你需要为每个基本类型数组编程,你需要这样一个方法(这对于C ++程序使用的内存基本没有区别,C ++程序将为每个使用的类型参数创建一个单独的方法。
答案 6 :(得分:3)
您可以使用IterableOf
中的Cactoos:
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"
);
答案 7 :(得分:2)
在Java 8或更高版本中,Iterable
是返回Iterator
的功能接口。
因此,您可以执行此操作。
int[] array = {1, 2, 3};
Iterable<Integer> iterable = () -> Arrays.stream(array).iterator();
for (int i : iterable)
System.out.println(i);
->
1
2
3
答案 8 :(得分: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
答案 9 :(得分:-2)
在java8中,IntSteam流可以装箱为整数流。
public static Iterable<Integer> toIterable(int[] ints) {
return IntStream.of(ints).boxed().collect(Collectors.toList());
}
我认为性能很重要,取决于数组的大小。