2012-02-08 14 views
12

Czy ktoś wie, jak dołączyć do wielu iteratorów w Javie? Rozwiązanie, które znalazłem najpierw iteracyjnie, a następnie przejście do następnego. Jednak to, czego chcę, to wywołanie metody next(), która najpierw zwraca pierwszy element z pierwszego iteratora. Następnym razem, gdy zostanie wywołana funkcja next(), zwraca pierwszy element z drugiego iteratora i tak dalej.dołącz do wielu iteratorów w java

Dzięki

+0

wielu iteratorów do samej kolekcji lub każdego innego iteratora z kolekcji? – kosa

+2

Yikes: http://stackoverflow.com/questions/3610261/is-it-possible-to-merge-iterators-in-java –

+0

@RobertPeters Tak wygląda dupe. flyingfromchina, czy możesz podać przykład tego, co chcesz wyjaśnić pytanie? – daveslab

Odpowiedz

10

Korzystanie Guava'sAbstractIterator dla uproszczenia:

final List<Iterator<E>> theIterators; 
return new AbstractIterator<E>() { 
    private Queue<Iterator<E>> queue = new LinkedList<Iterator<E>>(theIterators); 
    @Override protected E computeNext() { 
    while(!queue.isEmpty()) { 
     Iterator<E> topIter = queue.poll(); 
     if(topIter.hasNext()) { 
     E result = topIter.next(); 
     queue.offer(topIter); 
     return result; 
     } 
    } 
    return endOfData(); 
    } 
}; 

To daje pożądany „z przeplotem” porządek, to jest wystarczająco inteligentny, aby radzić sobie ze zbiorów o różnych rozmiarach, i to dość zwarte. (Możesz użyć wartości ArrayDeque zamiast LinkedList dla prędkości, zakładając, że korzystasz z Java 6+.)

Jeśli naprawdę, naprawdę nie możesz tolerować innej biblioteki innej firmy, możesz mniej lub bardziej zrobić to samo z jakąś dodatkową pracę, tak:

return new Iterator<E>() { 
    private Queue<Iterator<E>> queue = new LinkedList<Iterator<E>>(theIterators); 
    public boolean hasNext() { 
    // If this returns true, the head of the queue will have a next element 
    while(!queue.isEmpty()) { 
     if(queue.peek().hasNext()) { 
     return true; 
     } 
     queue.poll(); 
    } 
    return false; 
    } 
    public E next() { 
    if(!hasNext()) throw new NoSuchElementException(); 
    Iterator<E> iter = queue.poll(); 
    E result = iter.next(); 
    queue.offer(iter); 
    return result; 
    } 
    public void remove() { throw new UnsupportedOperationException(); } 
}; 

Dla porównania, „wszystko iter1 wszystkie iter2, etc” zachowanie można również uzyskać za pomocą Iterators.concat(Iterator<Iterator>) i jego przeciążenia.

-1

Najprostszym rozwiązaniem jest

for(Type1 t1: collection1) 
    for(Type2 t2: collection2) 

To będzie działać, jeśli to, co chcesz, aby wykonać połączenie między zbiorami.

Jeśli chcesz powtórzyć dwie kolekcje, wystarczy użyć dwóch pętli lub utworzyć kolekcję z obydwoma.

for(Type t1: collection1) 
    process(t1); 

for(Type t2: collection2) 
    process(t2); 

Jeśli chcesz przeplatać Iteratory, możesz użyć tablicy.

Iterator[] iters = { iter1, iter2, ... }; 
boolean finished; 
do { 
    finished = true; 
    for(Iterator it: iters) { 
    if (it.hasNext()) { 
     Object obj = it.next(); 
     // process 
     finished = false; 
    } 
    } 
} while(!finished); 
+1

Hmmm Myślę, że skutecznie chce Coll1.get (0), Coll2.get (0), Coll1.get (1), Coll2.get (1) - tj. Przepleciony, nie zagnieżdżony – Bohemian

+5

Nie sądzę, że zrobi to, co jest poprosił, prawda? –

+0

Czy to nie byłoby zbyteczne? Dla każdej pozycji w t1, wszystkie pozycje w t2 ?? – noMAD

3

Wygląda na to, że chcesz przeplatać . Coś takiego - zupełnie niesprawdzone ...

public class InterleavingIterable<E> implements Iterable<E> { 

    private final Iterable<? extends E> first; 
    private final Iterable<? extends E> second; 

    public InterleavingIterable(Iterable<? extends E> first, 
           Iterable<? extends E> second) { 
     this.first = first; 
     this.second = second; 
    } 

    public Iterator<E> iterator() { 
     return new InterleavingIterator<E>(first.iterator(), 
              second.iterator()); 
    } 

    private static class InterleavingIterator<E> implements Iterator<E> { 

     private Iterator<? extends E> next; 
     private Iterator<? extends E> current; 

     private InterleavingIterator(Iterator<? extends E> first, 
            Iterator<? extends E> second) { 
      next = first; 
      current = second; 
     } 

     public boolean hasNext() { 
      return next.hasNext() || (current != null && current.hasNext()); 
     } 

     public E next() throws NoSuchElementException { 
      if (next.hasNext()) { 
       E ret = next.next(); 
       if (current != null) { 
        Iterator<? extends E> tmp = current; 
        current = next; 
        next = tmp; 
       } 
       return ret; 
      } else { 
       // Nothing left in next... check "current" 
       if (current == null || !current.hasNext()) { 
        throw new NoSuchElementException(); 
       } 
       next = current; 
       current = null; 
       return current.next(); 
      } 
     } 

     public void remove() { 
      throw new UnsupportedOperationException(); 
     } 
    } 
} 
0

Edit: Ups, błędnie interpretowane Twoje pytanie. rzeczywiście trzeba iterator przeplatania, zamiast iterator związku:

class InterleavingIterator<T> implements Iterator<T> { 

    private final Iterator<T> internalIter; 

    public InterleavingIterator(final Iterator<T>... iterators) { 
     final LinkedList<Iterator<T>> iteratorQueue = new LinkedList<Iterator<T>>(); 
     for (final Iterator<T> loopIter : iterators) { 
      if (loopIter.hasNext()) { 
       iteratorQueue.push(loopIter); 
      } 
     } 

     // create the interleaving 
     final LinkedList<T> internalList = new LinkedList<T>(); 
     while (!iteratorQueue.isEmpty()) { 
      final Iterator<T> loopIter = iteratorQueue.pop(); 
      internalList.add(loopIter.next()); 
      if (loopIter.hasNext()) { 
       iteratorQueue.push(loopIter); 
      } 
     } 
     internalIter = internalList.iterator(); 
    } 

    public boolean hasNext() { 
     return internalIter.hasNext(); 
    } 

    public T next() { 
     return internalIter.next(); 
    } 

    public void remove() { 
     throw new UnsupportedOperationException("remove() unsupported"); 
    } 
} 

zmienił End.

Musisz użyć iterator związek, coś takiego:

import java.util.Collections; 
import java.util.Iterator; 
import java.util.LinkedList; 

public class CompoundIterator<T> implements Iterator<T> { 

    private final LinkedList<Iterator<T>> iteratorQueue; 
    private Iterator<T> current; 

    public CompoundIterator(final Iterator<T>... iterators) { 
     this.iteratorQueue = new LinkedList<Iterator<T>>(); 
     for (final Iterator<T> iterator : iterators) { 
      iteratorQueue.push(iterator); 
     } 
     current = Collections.<T>emptyList().iterator(); 
    } 

    public boolean hasNext() { 
     final boolean curHasNext = current.hasNext(); 
     if (!curHasNext && !iteratorQueue.isEmpty()) { 
      current = iteratorQueue.pop(); 
      return current.hasNext(); 
     } else { 
      return curHasNext; 
     } 
    } 

    public T next() { 
     if (current.hasNext()) { 
      return current.next(); 
     } 
     if (!iteratorQueue.isEmpty()) { 
      current = iteratorQueue.pop(); 
     } 
     return current.next(); 
    } 

    public void remove() { 
     throw new UnsupportedOperationException("remove() unsupported"); 
    } 
}