将Iterator转换为ArrayList
给定Iterator<Element>
,我们如何以尽可能最快和最快的方式将该迭代器转换为ArrayList<Element>
(或List<Element>
),以便我们可以使用ArrayList
的操作,比如get(index)
add(element)
等
最好使用像番石榴一样的图书馆:
import com.google.common.collect.Lists; Iterator<Element> myIterator = ... //some iterator List<Element> myList = Lists.newArrayList(myIterator);
另一个番石榴的例子:
ImmutableList.copyOf(myIterator);
或Apache Commons作品集 :
import org.apache.commons.collections.IteratorUtils; Iterator<Element> myIterator = ...//some iterator List<Element> myList = IteratorUtils.toList(myIterator);
在Java 8中,可以使用已添加到Iterator
接口的新的forEachRemaining
方法:
List<Element> list = new ArrayList<>(); iterator.forEachRemaining(list::add);
你可以像下面这样将一个迭代器复制到一个新的列表中:
Iterator<String> iter = list.iterator(); List<String> copy = new ArrayList<String>(); while (iter.hasNext()) copy.add(iter.next());
这是假设列表包含string。 实际上没有更快的方式来从一个迭代器重新创build一个列表,你坚持手动遍历它,并将每个元素复制到一个新的适当types的列表。
编辑:
下面是一个以types安全的方式将迭代器复制到新列表的通用方法:
public static <T> List<T> copyIterator(Iterator<T> iter) { List<T> copy = new ArrayList<T>(); while (iter.hasNext()) copy.add(iter.next()); return copy; }
像这样使用它:
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]
您也可以使用Apache commons-collections中的 IteratorUtils
,尽pipe它不支持generics:
List list = IteratorUtils.toList(iterator);
用java 8你可以使用这个解决scheme:
Iterable<Element> iterator = createIterator(); List<Element> array = StreamSupport .stream(iterator.spliterator(), false) .collect(Collectors.toList());
据我所知Collectors.toList()
创buildArrayList
实例。
其实在我看来,它在一条线上看起来也不错。
例如,如果您需要从某个方法返回List<Element>
:
return StreamSupport.stream(iter.spliterator(), false).collect(Collectors.toList());
List result = new ArrayList(); while (i.hasNext()){ result.add(i.next()); }
使用java.util.stream
简单Java 8相当简洁的解决scheme:
public static <T> ArrayList<T> toArrayList(final Iterator<T> iterator) { return StreamSupport .stream( Spliterators .spliteratorUnknownSize(iterator, Spliterator.ORDERED), false) .collect( Collectors.toCollection(ArrayList::new) ); }
使用谷歌番石榴 !
Iterable<String> fieldsIterable = ... List<String> fields = Lists.newArrayList(fieldsIterable);
++
从Cactoos尝试StickyList :
List<String> list = new StickyList<>(iterator);
免责声明:我是开发人员之一。
我只想指出一个看起来很明显的解决scheme,它不起作用:
List list = Stream.generate(iterator :: next).collect(Collectors.toList());
这是因为Stream#generate(Supplier<T>)
只能创build无限的stream,所以它不会指望它的参数抛出NoSuchElementException
(这就是Iterator#next()
会做的)。
如果迭代器→stream→列表方式是您的select,则应该使用xehpuk的答案 。
这里可以使用Iterator中的Java 8 forEachRemaining方法:
List<Element> elementList = new ArrayList<>(); iterator.forEachRemaining(elementList::add);
在这种情况下,如果你想要最快的方式,那么for loop
更好。
对于10,000 runs
的样本大小,迭代器需要40 ms
,for循环需要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));
这是假设列表包含string。