将Java数组转换为Iterable

问题描述 投票:122回答:9

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

最后,由于似乎有关于此的功课,避免发布家庭作业代码。

java arrays iterable
9个回答
108
投票
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();

-2
投票

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

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

我认为性能很重要,这取决于阵列的大小。


41
投票

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

27
投票

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

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元素数组列表,而不是创建由数组支持的列表。


8
投票

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

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

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


3
投票

首先,我只能同意Arrays.asList(T...)显然是Wrapper类型或具有非原始数据类型的数组的最佳解决方案。此方法在AbstractList类中调用一个简单的私有静态Arrays实现的构造函数,它基本上将给定的数组引用保存为字段,并通过覆盖所需的方法来模拟列表。 如果您可以为数组选择原始类型或Wrapper类型,我会在这种情况下使用Wrapper类型,但当然,它并不总是有用或必需。你可以做的只有两种可能性: 1)你可以为每个原始数据类型数组创建一个带静态方法的类(boolean, byte, short, int, long, char, float, double返回一个Iterable<WrapperType>。这些方法将使用Iterator的匿名类(除了Iterable),允许包含contains方法参数的引用(例如int[])作为字段以实现方法。 - >这种方法性能很好并且可以节省你的内存(除了新创建的方法的内存,即使使用Arrays.asList()会以相同的方式记忆) 2)由于数组没有方法(在你链接的一边读取),它们也不能提供Iterator实例。如果你真的懒得编写新类,你必须使用一个实现Iterable的已经存在的类的实例,因为除了实例化Iterable或子类型之外别无他法。 创建实现Iterable的现有Collection衍生的唯一方法是使用循环(除了你使用如上所述的匿名类)或者实例化一个Iterable实现类,其构造函数允许一个原始类型数组(因为Object[]不允许带有原语的数组类型元素)但据我所知,Java API没有这样的类。 循环的原因可以很容易地解释: 对于您需要的每个集合对象和原始数据类型不是对象。对象比原始类型大得多,因此它们需要为基本类型数组的每个元素生成必须生成的附加数据。这意味着如果两种方式(使用Arrays.asList(T...)或使用现有Collection)需要聚合对象,则需要为int[]数组的每个原始值创建包装器对象。第三种方式将按原样使用数组并在匿名类中使用它,因为我认为由于快速性能,它更可取。 还有第三种策略使用Object作为你要使用数组或Iterable的方法的参数,它需要类型检查来确定参数的类型,但是我不会像你通常那样推荐它需要考虑Object并不总是所需的类型,并且您需要为某些情况分开代码。 总而言之,这是Java有问题的通用类型系统的错误,它不允许使用原始类型作为通用类型,通过使用简单的Arrays.asList(T...)可以节省大量代码。所以你需要为每个基本类型数组编程,你需要这样一个方法(这对于C ++程序使用的内存基本上没有区别,C ++程序将为每个使用的类型参数创建一个单独的方法。


3
投票

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.