Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Limit a ListIterator to the first N elements (optimized)

What is a simple and fast way to get an iterator that returns at most N elements from the start of a List?

The simplest versions I could come up with are:

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

Unfortunately both versions create a temporary List which significantly affects performance as I am calling this method millions of times in a tight loop.

Are there any other library functions I could use for this?


Note: I cannot avoid iterating over the list as I am passing it to a method which takes an iterator as its argument and I cannot modify that class.

like image 724
finnw Avatar asked Oct 24 '09 18:10

finnw


4 Answers

You already know it's a list, so you can just call the List.subList(int fromIndex, int toIndex) method. As per the specification, the subList is backed by the original list, so it's not really creating a full blown List, just some kind of proxy object.

like image 80
RichN Avatar answered Sep 24 '22 23:09

RichN


Why not simply

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

I am not sure why you mind about the creation of that temporary list. It doesn't do anything I'd consider expensive. In fact, creating this list is by far cheaper than iterating over it, which I assume you do.

like image 34
meriton Avatar answered Sep 22 '22 23:09

meriton


Seems as if the feature will be added to guava, currently (as of r06) in beta:

public static <T> Iterator<T> limit(Iterator<T> iterator, int limitSize)
like image 26
Werner Lehmann Avatar answered Sep 23 '22 23:09

Werner Lehmann


This is a place where a Decorator works very well: your decorator keeps a count, which is incremented by next(), and used by control hasNext().

Example (intentionally incomplete):

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();
    }
like image 21
kdgregory Avatar answered Sep 26 '22 23:09

kdgregory