176

I have an Array of primitives, for example for int, int[] foo. It might be a small sized one, or not.

int foo[] = {1,2,3,4,5,6,7,8,9,0};

What is the best way to create an Iterable<Integer> from it?

Iterable<Integer> fooBar = convert(foo);

Notes:

Please do not answer using loops (unless you can give a good explanation on how the compiler do something smart about them?)

Also note that

int a[] = {1,2,3};
List<Integer> l = Arrays.asList(a);

Will not even compile

Type mismatch: cannot convert from List<int[]> to List<Integer>

Also check Why is an array not assignable to Iterable? before answering.

Also, if you use some library (e.g., Guava), please explain why this is the Best. ( Because its from Google is not a complete answer :P )

Last, since there seems to be a homework about that, avoid posting homeworkish code.

Community
  • 1
  • 1
ntg
  • 12,950
  • 7
  • 74
  • 95
  • possible duplicate of [Iterator for array](http://stackoverflow.com/questions/3912765/iterator-for-array) – NPE Apr 26 '12 at 14:38
  • Add them to an LinkedList then just return the iterator of that Set. –  Apr 26 '12 at 14:39

10 Answers10

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

Though you need to use an Integer array (not an int array) for this to work.

For primitives, you can use guava:

Iterable<Integer> fooBar = Ints.asList(foo);
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>15.0</version>
    <type>jar</type>
</dependency>

For Java8 with lambdas: (Inspired by Jin Kwon's answer)

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();
Stephan
  • 41,764
  • 65
  • 238
  • 329
fmucar
  • 14,361
  • 2
  • 45
  • 50
  • 13
    Two notes: 1) he has `int`, not `Integer` 2) `List` is already `Iterable` so the third line is pointless. – maksimov Apr 26 '12 at 14:51
  • 1
    he needs Iterable that why there is third line. – fmucar Apr 26 '12 at 14:55
  • 5
    2nd and 3rd lines are options i would say :) – fmucar Apr 26 '12 at 15:37
  • 1
    This is not part of a homework, I was just trying to avoid duplicating code for a debugging function processing the contents of an array or list... While looking around I did indeed find Arrays.asList(..);, but at least Eclipse seems to think it will not do what i want (e.g., It infers the result of Arrays.asList(foo) as a List, not List...) I found this interesting enough for a question... (-Breaking comment in parts cause of limits-) – ntg Apr 27 '12 at 07:19
  • 1
    In general one could think of a lot of ways to do it, but I was wondering what is the BEST (for example a loop would imho be mush slower compared to ...{well, the problem is I cannot think of anything!:) }) Also check http://stackoverflow.com/questions/1160081/why-is-an-array-not-assignable-to-iterable for a discussion on why, my question though is not why, but how, and what type of container would be best (why ArrayList? In fact,I could imagine some AbstractList wrapper using Generics.. , Probably depends on the size...) – ntg Apr 27 '12 at 07:19
  • BTW, I later remembered that I could use Arrays.toString() for what I needed, but converting should be useful in a bunch of cases... – ntg Apr 27 '12 at 07:20
  • 1
    A loop on array will not be slow, arrays are the fastest among all, as it is a sequence of memory blocks and looping means reading sequential memory blocks as is never slow comparing to other similar data objects. – fmucar Apr 27 '12 at 10:47
  • True, arrays are compact, which is why I keep the ints in the array. And looping is fast, but doing nothing is much faster :) I only want to be to see an existing int[] as Iterable, e.g., to reuse code, so I dont like to have to copy the whole thing... – ntg May 03 '12 at 06:21
  • Unless your array is like size of tens or hundreds of thousands in length, it should not make big difference. Copying it won't take long. Copying even millons won't be too long but this is all subjective. – fmucar May 03 '12 at 08:49
50

just my 2 cents:

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.");
            }
        };
    }
};
  • 10
    remove() is not neccessary in java 8, because it is a default method which throws UnsupportedOperationException. Only if you want to supply a better explanation message. – Alex Jun 06 '16 at 11:27
  • +1 I do something similar to create an `Iterator` from a `String`. Implementing your own `Iterator` seems like the only way to avoid needlessly iterating through all of the values to convert from the object type to the primitive type (via Guava's `Ints.asList()` for example), just to be able to get an `Iterator` from the `List` that was created. – spaaarky21 Apr 20 '17 at 16:16
  • 2
    You are right Alex. Default methods were added to Java 8. In 2013 I added this ancient piece of code here. – Joerg Ruethschilling Oct 18 '17 at 17:31
36

With Java 8, you can do this.

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();
Jin Kwon
  • 20,295
  • 14
  • 115
  • 184
20

Guava provides the adapter you want as Int.asList(). There is an equivalent for each primitive type in the associated class, e.g., Booleans for boolean, etc.

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

The suggestions above to use Arrays.asList won't work, even if they compile because you get an Iterator<int[]> rather than Iterator<Integer>. What happens is that rather than creating a list backed by your array, you created a 1-element list of arrays, containing your array.

BeeOnRope
  • 60,350
  • 16
  • 207
  • 386
  • just a note: the link isn't working anymore. Github link: https://github.com/google/guava/blob/master/guava/src/com/google/common/primitives/Ints.java – lue Feb 26 '20 at 17:45
  • Thanks @Passi, fixed (can't seem to find a Google supported way to link to javadoc anymore so I linked to the source you provided). – BeeOnRope Feb 27 '20 at 00:11
11

In Java 8 or later, Iterable is a functional interface returns Iterator. So you can do this.

static Iterable<Integer> convert(int[] array) {
    return () -> Arrays.stream(array).iterator();
}

and

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

output:

1
2
3
8

I had the same problem and solved it like this:

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

The iterator itself is a lazy UnmodifiableIterator but that's exactly what I needed.

mindas
  • 26,463
  • 15
  • 97
  • 154
4

First of all, I can only agree that Arrays.asList(T...) is clearly the best solution for Wrapper types or arrays with non-primtive datatypes. This method calls a constructor of a simple private static AbstractList implementation in the Arrays class which basically saves the given array reference as field and simulates a list by overriding the needed methods.

If you can choose between a primtive type or a Wrapper type for your array, I would use the Wrapper type for such situations but of course, it's not always useful or required. There would be only two possibilities you can do:

1) You can create a class with a static method for each primitive datatype array (boolean, byte, short, int, long, char, float, double returning an Iterable<WrapperType>. These methods would use anonymous classes of Iterator (besides Iterable) which are allowed to contain the reference of the comprising method's argument (for example an int[]) as field in order to implement the methods.

-> This approach is performant and saves you memory (except for the memory of the newly created methods, even though, using Arrays.asList() would take memory in the same way)

2) Since arrays don't have methods (as to be read on the side you linked) they can't provide an Iterator instance either. If you really are too lazy to write new classes, you must use an instance of an already existing class that implements Iterable because there is no other way around than instantiating Iterable or a subtype.
The ONLY way to create an existing Collection derivative implementing Iterable is to use a loop (except you use anonymous classes as described above) or you instantiate an Iterable implementing class whose constructor allows a primtive type array (because Object[] doesn't allow arrays with primitive type elements) but as far as I know, the Java API doesn't feature a class like that.

The reason for the loop can be explained easily:
for each Collection you need Objects and primtive datatypes aren't objects. Objects are much bigger than primitive types so that they require additional data which must be generated for each element of the primitive type array. That means if two ways of three (using Arrays.asList(T...) or using an existing Collection) require an aggregate of objects, you need to create for each primitive value of your int[] array the wrapper object. The third way would use the array as is and use it in an anonymous class as I think it's preferable due to fast performance.

There is also a third strategy using an Object as argument for the method where you want to use the array or Iterable and it would require type checks to figure out which type the argument has, however I wouldn't recommend it at all as you usually need to consider that the Object hasn't always the required type and that you need seperate code for certain cases.

In conclusion, it's the fault of Java's problematic Generic Type system which doesn't allow to use primitive types as generic type which would save a lot of code by using simply Arrays.asList(T...). So you need to program for each primitive type array, you need, such a method (which basically makes no difference to the memory used by a C++ program which would create for each used type argument a seperate method.

4

You can use IterableOf from Cactoos:

Iterable<String> names = new IterableOf<>(
  "Scott Fitzgerald", "Fyodor Dostoyevsky"
);

Then, you can turn it into a list using ListOf:

List<String> names = new ListOf<>(
  new IterableOf<>(
    "Scott Fitzgerald", "Fyodor Dostoyevsky"
  )
);

Or simply this:

List<String> names = new ListOf<>(
  "Scott Fitzgerald", "Fyodor Dostoyevsky"
);
yegor256
  • 102,010
  • 123
  • 446
  • 597
2

While a similar answer has already been sort of posted, I think the reason to use the new PrimitiveIterator.OfInt was not clear. A good solution is to use Java 8 PrimitiveIterator since it's specialized for primitive int types (and avoids the extra boxing/unboxing penalty):

    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
    }

Ref: https://doc.bccnsoft.com/docs/jdk8u12-docs/api/java/util/PrimitiveIterator.OfInt.html

Binod Pant
  • 267
  • 3
  • 7
-2

In java8 IntSteam stream can be boxed to stream of Integers.

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

I think performance matters based on the size of the array.