将Java数组转换为可迭代


150

我有一个原始数组,例如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),请解释为什么这是最好的。(因为来自Google的答案不是完整的:P)

最后,由于似乎有作业,因此请避免发布作业代码。



将它们添加到LinkedList,然后仅返回该Set的迭代器。

Answers:


117
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>

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

10
有两个注意事项:1)他有int,不是Integer2)List已经存在,Iterable所以第三行是毫无意义的。
maksimov

1
他需要Iterable,为什么会有第三行。
fmucar 2012年

5
第二行和第三行是选项,我会说:)
fmucar 2012年

1
这不是家庭作业的一部分,我只是在尝试避免为处理数组或列表内容的调试函数复制代码...环顾四周,我确实确实找到了Arrays.asList(..);,但至少Eclipse似乎认为它不会满足我的要求(例如,它以Array <int []>而不是List <Integer> ...的方式推断Arrays.asList(foo)的结果)问题...(
ntg 2012年

1
通常,人们可以想到很多方法来做到这一点,但是我想知道什么是最好的(例如,与...相比,循环的恕我直言要慢得多……{嗯,问题是我什么都没想到!: )})另外,请查看stackoverflow.com/questions/1160081/…,以获取有关为什么的讨论,我的问题不是为什么,而是如何,哪种类型的容器最好(为什么是ArrayList?实际上,我可以想象一些AbstractList包装使用泛型..,可能取决于大小...)
ntg 2012年

44

只是我的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.");
            }
        };
    }
};

9
在Java 8中,remove()并非必需,因为它是引发UnsupportedOperationException的默认方法。仅当您想提供更好的解释信息时。
Alex

+1我做类似创建一个东西Iterator<Character>String。实现自己的方法Iterator似乎是避免不必要地迭代所有值以从对象类型转换为原始类型(Ints.asList()例如,通过Guava进行转换)的唯一方法,只是为了能够IteratorList创建的对象中获取一个对象。
spaaarky21

2
你是对的亚历克斯。Java 8中添加了默认方法。2013年,我在此处添加了这段古老的代码。
Joerg Ruethschilling

29

使用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()。关联类中的每个原始类型都有一个等效项,例如Booleansfor 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元素列表。


请注意:该链接不再有效。Github上链接:github.com/google/guava/blob/master/guava/src/com/google/common/...
Orangle

感谢@Passi,已修复(似乎无法找到Google支持的链接至javadoc的方法,因此我已链接至您提供的源代码)。
BeeOnRope

8

我有同样的问题,并像这样解决了它:

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

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


7

在Java 8或更高版本中,Iterable是一个函数接口return Iterator。因此,您可以执行此操作。

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

->

1
2
3

3

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

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

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

->这种方法是高性能的,可以节省您的内存(尽管新创建的方法的内存除外,即使使用Arrays.asList()也会以相同的方式占用内存)

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

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

还有第三种策略Object,在要使用数组的方法中使用as参数,Iterable并且需要进行类型检查以弄清参数具有哪种类型,但是我通常不建议这样做。考虑到对象并非总是必需的类型,并且在某些情况下需要单独的代码。

总而言之,这是Java的有问题的Generic Type系统的错误,该系统不允许将基本类型用作泛型类型,而这将通过简单地使用而节省大量代码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"
);

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


-2

在java8中,可以将IntSteam流装箱为Integers流。

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

我认为性能取决于阵列的大小。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.