是否有可能在Java中合并迭代器?
是否有可能在Java中合并迭代器? 我有两个迭代器,我想合并/合并它们,这样我就可以一次遍历它们的元素(在同一个循环中)而不是两个步骤。 那可能吗?
请注意,两个列表中元素的数量可能不同,因此两个列表中的一个循环不是解决scheme。
Iterator<User> pUsers = userService.getPrimaryUsersInGroup(group.getId()); Iterator<User> sUsers = userService.getSecondaryUsersInGroup(group.getId()); while(pUsers.hasNext()) { User user = pUsers.next(); ..... } while(sUsers.hasNext()) { User user = sUsers.next(); ..... }
Guava (以前的Google Collections)有Iterators.concat 。
您可以创build自己的Iterator
接口的实现:
public class IteratorOfIterators implements Iterator { private final List<Iterator> iterators; public IteratorOfIterators(List<Iterator> iterators) { this.iterators = iterators; } public IteratorOfIterators(Iterator... iterators) { this.iterators = Arrays.asList(iterators); } public boolean hasNext() { /* implementation */ } public Object next() { /* implementation */ } public void remove() { /* implementation */ } }
(为了简洁起见,我还没有在generics中joingenerics) 。实现并不难,但也不是最微不足道的,你需要跟踪你正在迭代的迭代Iterator
,然后调用next()
你需要通过迭代器尽可能地迭代,直到你find一个返回true
的hasNext()
,或者你可以敲最后一个迭代器的末尾。
我不知道任何已经存在的实现。
更新:
我已经投了Andrew Duffy的回答 – 不需要重新发明轮子。 我真的需要深入研究番石榴。
我已经为可变数量的参数添加了另一个构造函数 – 几乎渐渐脱离了主题,因为如何在这里构造类并不是真正的兴趣,只是它的工作原理。
此外, Apache Commons Collection还有几个用于操作迭代器的类,如IteratorChain ,它包装了一些迭代器。
我还没有编写Java代码,这让我好奇我是否还“知道了”。
第一次尝试:
import java.util.Iterator; import java.util.Arrays; /* For sample code */ public class IteratorIterator<T> implements Iterator<T> { private final Iterator<T> is[]; private int current; public IteratorIterator(Iterator<T>... iterators) { is = iterators; current = 0; } public boolean hasNext() { while ( current < is.length && !is[current].hasNext() ) current++; return current < is.length; } public T next() { while ( current < is.length && !is[current].hasNext() ) current++; return is[current].next(); } public void remove() { /* not implemented */ } /* Sample use */ public static void main(String... args) { Iterator<Integer> a = Arrays.asList(1,2,3,4).iterator(); Iterator<Integer> b = Arrays.asList(10,11,12).iterator(); Iterator<Integer> c = Arrays.asList(99, 98, 97).iterator(); Iterator<Integer> ii = new IteratorIterator<Integer>(a,b,c); while ( ii.hasNext() ) System.out.println(ii.next()); } }
你当然可以使用更多的集合类,而不是一个纯粹的数组+索引计数器,但是这实际上比替代方法感觉更清洁。 还是我这些日子主要是写C?
无论如何,你去了。 你的问题的答案是“是的,可能”。
移动你的循环到一个方法,并将迭代器传递给方法。
void methodX(Iteartor x) { while (x.hasNext()) { .... } }
迭代器来自一个集合或一个集合。
为什么不使用已有的方法
Collection.addAll(Collection c);
然后从最后一个对象创build你的迭代器。
这样,你的迭代器将迭代这两个集合的所有内容。
我会重构原来的devise:
Iterator<User> pUsers = userService.getPrimaryUsersInGroup(group.getId()); Iterator<User> sUsers = userService.getSecondaryUsersInGroup(group.getId());
像这样的东西:
Iterator<User> users = userService.getUsersInGroup(group.getId(), User.PRIMARY, User.SECONDARY, ...);
你可以使用我的版本的可扩展的迭代器。 它使用迭代器的双端队列,这对我来说是有道理的:
import java.util.Deque; import java.util.Iterator; import java.util.concurrent.ConcurrentLinkedDeque; public class ExtendableIterator<T> implements Iterator<T> { public Deque<Iterator<T>> its = new ConcurrentLinkedDeque<Iterator<T>>(); public ExtendableIterator() { } public ExtendableIterator(Iterator<T> it) { this(); this.extend(it); } @Override public boolean hasNext() { // this is true since we never hold empty iterators return !its.isEmpty() && its.peekLast().hasNext(); } @Override public T next() { T next = its.peekFirst().next(); if (!its.peekFirst().hasNext()) { its.removeFirst(); } return next; } public void extend(Iterator<T> it) { if (it.hasNext()) { its.addLast(it); } } }
合并迭代器:
import static java.util.Arrays.asList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; public class ConcatIterator<T> implements Iterator<T> { private final List<Iterable<T>> iterables; private Iterator<T> current; @SafeVarargs public ConcatIterator(final Iterable<T>... iterables) { this.iterables = new LinkedList<>(asList(iterables)); } @Override public boolean hasNext() { checkNext(); return current != null && current.hasNext(); } @Override public T next() { checkNext(); if (current == null || !current.hasNext()) throw new NoSuchElementException(); return current.next(); } @Override public void remove() { if (current == null) throw new IllegalStateException(); current.remove(); } private void checkNext() { while ((current == null || !current.hasNext()) && !iterables.isEmpty()) { current = iterables.remove(0).iterator(); } } }
用于创buildIterable
的concat
方法:
@SafeVarargs public static <T> Iterable<T> concat(final Iterable<T>... iterables) { return () -> new ConcatIterator<>(iterables); }
简单的JUnittesting:
@Test public void testConcat() throws Exception { final Iterable<Integer> it1 = asList(1, 2, 3); final Iterable<Integer> it2 = asList(4, 5); int j = 1; for (final int i : concat(it1, it2)) { assertEquals(j, i); j++; } }
你可以试试ConcatIterator
的ConcatIterator :
Iterator<String> names = new ConcatIterator<>( Arrays.asList("Sarah", "Mary").iterator(), Arrays.asList("Jeff", "Johnny").iterator(), );
还要检查ConcatIterable
,它连接了Iterable
。
每个Iterator
对象拥有自己的内存位置( 地址 ),所以你不能简单地“合并”它们。 除非你扩展iterator
类并在那里写你自己的实现。
如果在两个迭代器中处理的对象数量相同,则另一种解决scheme是在一个循环中处理两个迭代器,如下所示:
while (iterator1.hasNext() && iterator2.hasNext()) { // code }