Reputation: 16931
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
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
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
Reputation: 105063
Try StickyList
from Cactoos:
List<String> list = new StickyList<>(iterable);
Disclaimer: I'm one of the developers.
Upvotes: 1
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
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
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
Reputation: 105063
You can also use IteratorUtils
from Apache commons-collections, although it doesn't support generics:
List list = IteratorUtils.toList(iterator);
Upvotes: 24
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
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
Reputation: 651
use google guava !
Iterable<String> fieldsIterable = ...
List<String> fields = Lists.newArrayList(fieldsIterable);
++
Upvotes: 1
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
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
Reputation: 951
List result = new ArrayList();
while (i.hasNext()){
result.add(i.next());
}
Upvotes: 5