Maksim
Maksim

Reputation: 16931

Convert Iterator to List

Given Iterator<Element>, how can we conveniently convert that Iterator to a List<Element>, so that we can use List's operations on it such as get(index), add(element), etc.

Upvotes: 297

Views: 351430

Answers (13)

Lais Lodi
Lais Lodi

Reputation: 11

I came to this issue when using Spring Boot Repository, where Iterable<Element> allIterables = repository.findAll() returns an Iterable.

My solution was to instantiate a new list List<Element> allElements = new ArrayList<>() and add all elements to my list using allIterables.forEach(allElements::add).

Upvotes: 1

apflieger
apflieger

Reputation: 1231

Without external dependency, here's a one-liner using Streams and java 16 toList().

Given an Iterator<?> iterator:

List<?> list = StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false).toList();

Upvotes: 8

yegor256
yegor256

Reputation: 105063

Try StickyList from Cactoos:

List<String> list = new StickyList<>(iterable);

Disclaimer: I'm one of the developers.

Upvotes: 1

Dub Nazar
Dub Nazar

Reputation: 532

Note there is a difference between Iterable and Iterator.

If you have an Iterable, then with Java 8 you can use this solution:

Iterable<Element> iterable = createIterable();
List<Element> array = StreamSupport
    .stream(iterable.spliterator(), false)
    .collect(Collectors.toList());

As I know Collectors.toList() creates ArrayList instance.

Actually in my opinion, it also looks good in one line.
For example if you need to return List<Element> from some method:

return StreamSupport.stream(iter.spliterator(), false).collect(Collectors.toList());

Upvotes: 31

Sasha
Sasha

Reputation: 4004

I just want to point out a seemingly obvious solution that will NOT work:

List list = Stream.generate(iterator::next)
    .collect(Collectors.toList());

That's because Stream#generate(Supplier<T>) can create only infinite streams, it doesn't expect its argument to throw NoSuchElementException (that's what Iterator#next() will do in the end).

The xehpuk's answer should be used instead if the Iterator→Stream→List way is your choice.

Upvotes: 2

Renaud
Renaud

Reputation: 16501

Better use a library like Guava:

import com.google.common.collect.Lists;

Iterator<Element> myIterator = ... //some iterator
List<Element> myList = Lists.newArrayList(myIterator);

Another Guava example:

ImmutableList.copyOf(myIterator);

or Apache Commons Collections:

import org.apache.commons.collections.IteratorUtils;

Iterator<Element> myIterator = ...//some iterator

List<Element> myList = IteratorUtils.toList(myIterator);       

Upvotes: 409

yegor256
yegor256

Reputation: 105063

You can also use IteratorUtils from Apache commons-collections, although it doesn't support generics:

List list = IteratorUtils.toList(iterator);

Upvotes: 24

xehpuk
xehpuk

Reputation: 8241

Pretty concise solution with plain Java 8 using java.util.stream:

public static <T> ArrayList<T> toArrayList(final Iterator<T> iterator) {
    return StreamSupport
        .stream(
            Spliterators
                .spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
        .collect(
                Collectors.toCollection(ArrayList::new)
    );
}

Upvotes: 10

Stuart Marks
Stuart Marks

Reputation: 132380

In Java 8, you can use the new forEachRemaining method that's been added to the Iterator interface:

List<Element> list = new ArrayList<>();
iterator.forEachRemaining(list::add);

Upvotes: 294

fedevo
fedevo

Reputation: 651

use google guava !

Iterable<String> fieldsIterable = ...
List<String> fields = Lists.newArrayList(fieldsIterable);

++

Upvotes: 1

vikiiii
vikiiii

Reputation: 9456

Here in this case if you want the fastest way possible then for loop is better.

The iterator over a sample size of 10,000 runs takes 40 ms where as for loop takes 2 ms

        ArrayList<String> alist = new ArrayList<String>();  
        long start, end;  

        for (int i = 0; i < 1000000; i++) {  
            alist.add(String.valueOf(i));  
        }  

        ListIterator<String> it = alist.listIterator();      

        start = System.currentTimeMillis();  
        while (it.hasNext()) {  
            String s = it.next();  
        }  
        end = System.currentTimeMillis();  

        System.out.println("Iterator start: " + start + ", end: " + end + ", delta: "  
            + (end - start));  
        start = System.currentTimeMillis();  
        int ixx = 0;  
        for (int i = 0; i < 100000; i++) {  
            String s = alist.get(i);  
        }  

        System.out.println(ixx);  
        end = System.currentTimeMillis();  
        System.out.println("for loop start: " + start + ", end: " + end + ", delta: "  
            + (end - start));  

That's assuming that the list contains strings.

Upvotes: -3

&#211;scar L&#243;pez
&#211;scar L&#243;pez

Reputation: 236004

You can copy an iterator to a new list like this:

Iterator<String> iter = list.iterator();
List<String> copy = new ArrayList<String>();
while (iter.hasNext())
    copy.add(iter.next());

That's assuming that the list contains strings. There really isn't a faster way to recreate a list from an iterator, you're stuck with traversing it by hand and copying each element to a new list of the appropriate type.

EDIT :

Here's a generic method for copying an iterator to a new list in a type-safe way:

public static <T> List<T> copyIterator(Iterator<T> iter) {
    List<T> copy = new ArrayList<T>();
    while (iter.hasNext())
        copy.add(iter.next());
    return copy;
}

Use it like this:

List<String> list = Arrays.asList("1", "2", "3");
Iterator<String> iter = list.iterator();
List<String> copy = copyIterator(iter);
System.out.println(copy);
> [1, 2, 3]

Upvotes: 74

Akvel
Akvel

Reputation: 951

List result = new ArrayList();
while (i.hasNext()){
    result.add(i.next());
}

Upvotes: 5

Related Questions