10

什么是获取从 a 的开头最多返回 N 个元素的迭代器的简单快速的方法List

我能想到的最简单的版本是:

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

不幸的是,这两个版本都创建了一个临时的List,这会显着影响性能,因为我在一个紧密的循环中调用了这个方法数百万次。

我可以为此使用任何其他库函数吗?


注意:我无法避免迭代列表,因为我将它传递给一个以迭代器作为参数的方法,并且我无法修改该类。

4

7 回答 7

15

您已经知道它是一个列表,因此您可以调用该List.subList(int fromIndex, int toIndex)方法。根据规范, subList 由原始列表支持,因此它并不是真正创建一个完整的List,只是某种代理对象。

于 2009-10-24T19:16:05.267 回答
8

似乎该功能将被添加到番石榴中,目前(截至 r06)处于测试阶段:

public static <T> Iterator<T> limit(Iterator<T> iterator, int limitSize)
于 2010-08-05T01:29:10.357 回答
5

这是一个装饰器工作得很好的地方:你的装饰器保持一个计数,它以 递增next(),并由 control 使用hasNext()

示例(故意不完整):

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();
    }
于 2009-10-24T18:59:17.183 回答
5

为什么不简单

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

我不确定您为什么介意创建该临时列表。它没有做任何我认为昂贵的事情。事实上,创建这个列表比迭代它要便宜得多,我假设你会这样做。

于 2009-10-24T19:14:20.543 回答
2

ArrayList.sublist(int,int)方法不会创建原始列表的副本。相反,它返回一个包装原始 ArrayList 的 SubList 实例。从 Array 派生的子列表返回的迭代器也不会复制。

所以我的建议是尝试使用ArrayList作为您的基本列表类型和sublist方法。如果这还不够快,请实现您自己的变体ArrayList来实现一个limitedLengthIterator方法。例如,您应该能够摆脱检查并发修改的代码。

于 2009-10-25T14:27:57.957 回答
1

如果您担心性能,请不要使用迭代器,请在数组上使用索引。这将提供更好的性能。获取数组的前 N ​​个元素是微不足道的。

于 2009-10-25T14:01:22.710 回答
0

这个版本比其他任何例子都快:

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

如果无论如何都必须创建临时列表,则 anArrayList比其他库方法返回的修饰列表更快。

我的猜测是ArrayList在虚拟机中得到了一些特殊的待遇。

也许这对于很长的列表效率低下,但我的列表很短(几乎总是少于 50 个元素。)

于 2009-10-25T12:17:20.140 回答