java 将 ListIterator 限制为前 N 个元素(优化)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1618759/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Limit a ListIterator to the first N elements (optimized)
提问by finnw
What is a simple and fast way to get an iterator that returns at most N elements from the start of a List?
获取从 a 开头最多返回 N 个元素的迭代器的简单快速方法是List什么?
The simplest versions I could come up with are:
我能想到的最简单的版本是:
#1:
#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:
#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 Listwhich significantly affects performance as I am calling this method millions of times in a tight loop.
不幸的是,这两个版本都创建了一个临时的List,这会显着影响性能,因为我在一个紧密的循环中调用了这个方法数百万次。
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.
注意:我无法避免遍历列表,因为我将它传递给一个将迭代器作为参数的方法,并且我无法修改该类。
采纳答案by Werner Lehmann
回答by RichN
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.
您已经知道它是一个列表,因此您只需调用该List.subList(int fromIndex, int toIndex)方法即可。根据规范, subList 由原始列表支持,因此它并没有真正创建一个完整的List,只是某种代理对象。
回答by kdgregory
This is a place where a Decoratorworks very well: your decorator keeps a count, which is incremented by next(), and used by control hasNext().
这是一个装饰器工作得很好的地方:你的装饰器保持一个计数,它增加了next(),并由 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();
}
回答by meriton
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.
我不知道你为什么介意创建那个临时列表。它不会做任何我认为昂贵的事情。事实上,创建这个列表比迭代它便宜得多,我假设你会这样做。
回答by Stephen C
The ArrayList.sublist(int,int)method does not create a copy of the original list. Instead it returns a SubList instance that wraps the original ArrayList. The iterator returned by the sublist derived from Array doesn't make a copy either.
该ArrayList.sublist(int,int)方法不会创建原始列表的副本。相反,它返回一个包装原始 ArrayList 的 SubList 实例。从 Array 派生的子列表返回的迭代器也不进行复制。
So my advice is to try using ArrayListas your base list type and the sublistmethod. If that is not fast enough, implement your own variant of ArrayListthat implements a limitedLengthIteratormethod. For example, you should be able to get rid of the code that checks for concurrent modifications.
所以我的建议是尝试使用ArrayList作为您的基本列表类型和sublist方法。如果这还不够快,请实现您自己的ArrayList实现limitedLengthIterator方法的变体。例如,您应该能够摆脱检查并发修改的代码。
回答by Peter Lawrey
If you are concerned about performance, don't use an Iterator, use an index on an array. This will give much better performance. Getting the first N elements of an array is trivial.
如果您担心性能,请不要使用迭代器,而是使用数组的索引。这将提供更好的性能。获取数组的前 N 个元素是微不足道的。
回答by finnw
This version turns out to be faster than any of the other examples:
事实证明,这个版本比任何其他示例都要快:
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();
}
If the temporary list has to be created anyway, an ArrayListis faster than the decorated lists returned by the other library methods.
如果无论如何都必须创建临时列表, anArrayList比其他库方法返回的装饰列表要快。
My guess is that ArrayListis getting some special treatment within the VM.
我的猜测是ArrayList在 VM 中得到了一些特殊处理。
Maybe this would be inefficient for very long lists, but my lists are short (nearly always fewer than 50 elements.)
对于很长的列表,这可能效率低下,但我的列表很短(几乎总是少于 50 个元素。)

