2012-02-08 19 views
12

¿Alguien sabe cómo unir múltiples iteradores en Java? La solución que encontré itera a través de un iterador primero, y luego pasa al siguiente. Sin embargo, lo que quiero es que cuando se llame a next(), primero devuelva el primer elemento del primer iterador. La próxima vez que se llama a next(), devuelve el primer elemento del segundo iterador, y así sucesivamente.unir varios iteradores en java

Gracias

+0

iteradores múltiples a misma colección o cada iterador de diferentes colección? – kosa

+2

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

+0

@RobertPeters Sí parece un tonto. flyingfromchina, ¿puedes publicar un ejemplo de lo que quieres aclarar? – daveslab

Respuesta

10

Usando Guava'sAbstractIterator por simplicidad:

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(); 
    } 
}; 

Esto le dará la orden "entrelazado" deseado, es lo suficientemente inteligente como para hacer frente a las colecciones que tienen diferentes tamaños, y es bastante compacto. (Puede usar ArrayDeque en lugar de LinkedList para obtener velocidad, suponiendo que está en Java 6+.)

Si realmente no puede tolerar otra biblioteca de terceros, puede hacer más o menos lo mismo lo mismo con un poco de trabajo adicional, así:

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(); } 
}; 

como referencia, el "todos iter1, todos iter2, etc" comportamiento puede también obtenerse utilizando Iterators.concat(Iterator<Iterator>) y sus sobrecargas.

-1

El enfoque más simple es

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

Esto funcionará si lo que quiere que se realice una unión entre colecciones.

Si desea iterar dos colecciones, solo usaría dos bucles o crearía una colección con ambos.

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

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

Si desea intercalar los iteradores, puede utilizar una matriz.

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 Creo que efectivamente quiere Coll1.get (0), Coll2.get (0), Coll1.get (1), Coll2.get (1) - es decir, intercalado, no anidado – Bohemian

+5

No creo que va a hacer lo que es solicitado, ¿verdad? –

+0

¿No funcionaría de forma redundante? Para cada artículo en t1, ¿todos los artículos en t2? – noMAD

3

Parece que desea un entrelazado . Algo como esto - no está comprobado ...

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

Editar: Vaya, malinterpretado su pregunta. que realmente necesita un iterador de intercalación, en lugar de un iterador compuesto:

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"); 
    } 
} 

Fin de edición.

Es necesario utilizar un iterador compuesto, algo así como:

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"); 
    } 
}