是否可以在Java中合并迭代器?我有两个迭代器,我想组合/合并它们,以便我可以一次性迭代它们的元素(在同一个循环中)而不是两个步骤。那可能吗?
请注意,两个列表中的元素数量可能不同,因此两个列表中的一个循环不是解决方案。
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();
.....
}
答案 0 :(得分:49)
Guava(以前称为Google Collections)有Iterators.concat。
答案 1 :(得分:18)
Apache Commons Collection还有几个用于操作迭代器的类,如IteratorChain,它包含了许多迭代器。
答案 2 :(得分:16)
您可以创建自己的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 */ }
}
(为了简洁起见,我没有在迭代器中添加泛型。)实现并不是太难,但不是最简单的,你需要跟踪哪个{{1}你正在迭代,调用Iterator
你需要尽可能迭代通过迭代器,直到你找到一个返回next()
的{{1}},或者你可以点击最后一个迭代器的结尾。
我不知道任何已经存在的实现。
更新
我已经投了Andrew Duffy's回答 - 没有必要重新发明轮子。我真的需要更深入地研究番石榴。
我为可变数量的参数添加了另一个构造函数 - 几乎脱离主题,因为这里构造类的方式并不是真正令人感兴趣的,只是它的工作原理。
答案 3 :(得分:12)
我有一段时间没有编写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());
}
}
你当然可以使用更多的Collection类而不是纯数组+索引计数器,但这实际上感觉比替代方案更清晰。或者我现在偏向于写作大部分是C?
无论如何,你去吧。你回答的问题是“是的,可能”。
答案 4 :(得分:3)
将循环移动到方法并将迭代器传递给方法。
void methodX(Iteartor x) {
while (x.hasNext()) {
....
}
}
答案 5 :(得分:3)
迭代器来自集合或集合
为什么不使用已有的方法
Collection.addAll(Collection c);
然后从最后一个对象创建迭代器
这样,你的迭代器将遍历两个集合的所有内容。
答案 6 :(得分:3)
public class IteratorJoin<T> implements Iterator<T> {
private final Iterator<T> first, next;
public IteratorJoin(Iterator<T> first, Iterator<T> next) {
this.first = first;
this.next = next;
}
@Override
public boolean hasNext() {
return first.hasNext() || next.hasNext();
}
@Override
public T next() {
if (first.hasNext())
return first.next();
return next.next();
}
}
答案 7 :(得分:2)
您可以使用可扩展迭代器的my version。它使用了一个双端的迭代器队列,这对我来说很有意义:
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);
}
}
}
答案 8 :(得分:2)
从Java 8开始,可以使用Stream API在没有外部依赖的情况下完成此操作。这也允许将迭代器与其他类型的流串联。
Streams.concat(StreamSupport.stream(<iter1>, false), StreamSupport.stream(<iter2>, false));
答案 9 :(得分:1)
我会重构原始设计:
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, ...);
答案 10 :(得分:1)
Merged Iterator:
public function groups($eventId)
{
return Group::where('event_id', $eventId)->with('individuals')->paginate(5);
}
创建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();
}
}
}
的{{1}}方法:
concat
简单的JUnit测试:
Iterable
答案 11 :(得分:1)
您可以尝试ConcatIterator
中的Cactoos:
Iterator<String> names = new ConcatIterator<>(
Arrays.asList("Sarah", "Mary").iterator(),
Arrays.asList("Jeff", "Johnny").iterator(),
);
同时检查ConcatIterable
,它连接Iterable
s。
答案 12 :(得分:0)
每个Iterator
对象都拥有自己的内存位置(地址),因此您无法简单地“合并”它们。除非你扩展iterator
类并在那里编写自己的实现。
如果你在两个迭代器中处理相同数量的对象,另一种解决方案是在一个循环中处理两个迭代器,如下所示:
while (iterator1.hasNext() && iterator2.hasNext()) {
// code
}
答案 13 :(得分:0)
在Apache Commons Collections中,有public static <E> Iterator<E> org.apache.commons.collections4.IteratorUtils.chainedIterator(Collection<Iterator<? extends E>> iterators)
说
获取一个迭代器,该迭代器一个接一个地迭代一系列迭代器。
这应该是您想要的。
import java.util.Arrays;
import java.util.Iterator;
import org.apache.commons.collections4.IteratorUtils;
//also works: import org.apache.commons.collections.IteratorUtils;
class Scratch {
public static void main( String[] args ) {
final Iterator<String> combinedIterator = IteratorUtils.chainedIterator(
Arrays.asList( "a", "b", "c" ).iterator(),
Arrays.asList( "1", "2", "3" ).iterator()
);
while( combinedIterator.hasNext() ){
System.out.println( combinedIterator.next() );
}
// "abc123" will have been printed out
}
}