Given Iterator<Element>
, how can we convert that Iterator
to ArrayList<Element>
(or List<Element>
) in the best and fastest way possible, so that we can use ArrayList
's operations on it such as get(index)
, add(element)
, etc.
问题:
回答1:
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);
回答2:
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);
回答3:
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]
回答4:
You can also use IteratorUtils
from Apache commons-collections, although it doesn't support generics:
List list = IteratorUtils.toList(iterator);
回答5:
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());
回答6:
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)
);
}
回答7:
List result = new ArrayList();
while (i.hasNext()){
result.add(i.next());
}
回答8:
Java 8 forEachRemaining method in Iterator can be used here :
List<Element> elementList = new ArrayList<>();
iterator.forEachRemaining(elementList::add);
回答9:
Try StickyList
from Cactoos:
List<String> list = new StickyList<>(iterator);
Disclaimer: I'm one of the developers.
回答10:
use google guava !
Iterable<String> fieldsIterable = ...
List<String> fields = Lists.newArrayList(fieldsIterable);
++
回答11:
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.
回答12:
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.