Frage

Was ist eine einfache und schnelle Möglichkeit, einen Iterator zu erhalten, die von Anfang an einem List höchstens N Elementen zurückzugibt?

Die einfachsten Versionen ich tun konnte, sind:

# 1:

import com.google.common.collect.Iterators;

// ...

public static <E> Iterator<E> lengthLimitedIterator(Iterable<E> source, int maxLen) {
    return Iterators.partition(source.iterator(), maxLen).next().iterator();
}

# 2:

public static <E> Iterator<E> lengthLimitedIterator(List<E> source, int maxLen) {
    return source.subList(0, Math.min(source.size(), maxLen)).iterator();
}

Leider schaffen beide Versionen eine temporäre List, die die Leistung erheblich beeinflusst, wie ich in einer engen Schleife dieser Methode Millionen Mal nenne.

Gibt es andere Bibliotheksfunktionen ich dafür verwenden könnte?


. Hinweis: Ich kann nicht umhin, über die Liste iterieren, wie ich es auf ein Verfahren bin vorbei, die einen Iterator als Argument und ich kann diese Klasse nicht ändern

War es hilfreich?

Lösung

Es scheint, als ob die Funktion Guave hinzugefügt werden, die derzeit (Stand R06) in der beta:

public static <T> Iterator<T> limit(Iterator<T> iterator, int limitSize)

Andere Tipps

Sie wissen bereits, es ist eine Liste, so dass Sie nur die List.subList(int fromIndex, int toIndex) Methode aufrufen. Gemäß der Beschreibung wird der subList von der ursprünglichen Liste gesichert, so ist es nicht wirklich eine vollständige geblasenen List, nur eine Art von Proxy-Objekt zu schaffen.

Dies ist ein Ort, an dem ein Decorator funktioniert sehr gut: Ihr Dekorateur eine Zählung hält, die von next() erhöht wird, und durch Steuer hasNext() verwendet.

Beispiel (absichtlich unvollständig):

public class LengthLimitedIterator<T>
implements Iterator<T>
{
    private Iterator<T> _wrapped;
    private int _length;
    private int _count;

    public LengthLimitedIterator(Iterator<T> wrapped, int length)
    {
        _wrapped = wrapped;
        _length = length;
    }


    public boolean hasNext()
    {
        if (_count < _length)
            return _wrapped.hasNext();
        return false;
    }

    public T next()
    {
        // FIXME - add exception if count >= length
        _count++;
        return _wrapped.next();
    }

Warum nicht einfach

list.subList(0, 42).iterator();

Ich bin nicht sicher, warum Sie über die Schaffung dieser temporären Liste kümmern. Es tut nichts ich teuer betrachten würde. In der Tat ist diese Liste zu schaffen bei weitem billiger als über sie iterieren, die ich nehme an, Sie tun.

Die ArrayList.sublist(int,int) Methode erstellen keine Kopie der ursprünglichen Liste. Stattdessen gibt es eine Unterliste Instanz, die die ursprüngliche Arraylist wickelt. Der Iterator der sublist abgeleitet von Array zurückgegeben keine Kopie entweder machen.

Also mein Rat ist mit ArrayList als Basistyp und der sublist Methode zu versuchen. Wenn das nicht schnell genug ist, eine eigene Variante von ArrayList implementieren, die eine limitedLengthIterator Methode implementiert. Zum Beispiel sollten Sie in der Lage sein, den Code, um loszuwerden, die für die gleichzeitigen Änderungen überprüft.

Wenn Sie über die Leistung betrifft, nicht einen Iterator verwenden, einen Index für ein Array verwenden. Dies gibt viel bessere Leistung. Erhalten der ersten N Elemente eines Arrays ist trivial.

Diese Version erweist sich als schneller als alle anderen Beispiele:

public static <E> Iterator<E> lengthLimitedIterator(List<E> source, int maxLen) {
    maxLen = Math.min(maxLen, source.size());
    ArrayList<E> tempList = new ArrayList<E>(maxLen);
    for (int i = 0; i < maxLen; ++ i) {
       tempList.add(source.get(i));
    }
    return tempList.iterator();
}

Wenn die temporäre Liste ohnehin erstellt werden, ein ArrayList ist schneller als die eingerichteten Listen von den anderen Bibliothek Methoden zurückgegeben.

Meine Vermutung ist, dass ArrayList ist eine besondere Behandlung innerhalb der VM zu bekommen.

Vielleicht wäre dies für sehr lange Listen ineffizient sein, aber meine Listen sind kurz (fast immer weniger als 50 Elemente).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top