我正在寻找一种优雅的方式,可能是用Guava来包装Iterable / Iterator,这样新的Iterable / Iterator
Guava似乎具有限制输入的功能(http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Iterables.html#limit(java.lang.Iterable,%20int),但不是从给定索引开始。我需要两者的组合。
你会怎么做?
答案 0 :(得分:4)
您可以将skip
用于此目的。
返回跳过其第一个numberToSkip元素的iterable视图。
例如,以下内容将为您提供一个Iterable,它会跳过前两个元素,然后将其限制为下一个元素:
List<Integer> list = [0, ..., 10];
Iterable<Integer> iterable = Iterables.limit(Iterables.skip(list, 2), 5); //[2, 3, 4, 5, 6]
请注意,参数不被视为索引,而是被视为要跳过(或限制)的元素的数字。但是,如果您知道要跳过多少元素,那么计算结束索引很容易。
import static com.google.common.collect.Iterables.limit;
import static com.google.common.collect.Iterables.skip;
...
static <T> Iterable<T> bounded(Iterable<T> iterable, int startIndex, int lastIndex) {
return limit(skip(iterable, startIndex+1), lastIndex-startIndex);
}
bounded(list, 2, 5)//[3, 4, 5]
如果底层数据结构使用索引(例如ArrayList
)对其元素进行排序,则后者才有意义。
但它也可能是HashSet
,并且在HashSet
中的某个索引开始和停止是没有意义的,因为它是无序的(即不要期望limit(skip(mySet, 2), 5)
会为您提供元素3, 4, 5
返回
使用java-8,您可以使用新的Stream API,它也具有跳过和限制方法。
static <T> Iterable<T> bounded(Iterable<T> iterable, int startIndex, int lastIndex) {
return StreamSupport.stream(iterable.spliterator(), false)
.skip(startIndex+1)
.limit(lastIndex-startIndex)
.collect(Collectors.toList());
}
答案 1 :(得分:0)
实际上没有一种有效的方法,因为迭代器是如此通用。没有什么可以告诉你底层数据结构有任何方法可以跳到中间来找到给定的索引。想想链接列表:你可以通过遍历列表来索引 k 的唯一方法。
您需要在Iterator
周围创建一个包装器,并将接口方法委托给基础Iterator
,但为hasNext()
和{{1}添加一些额外的逻辑方法和next()
如果需要删除支持。第一次调用其中一个时,它需要遍历底层列表以查找起始索引,并设置一个私有标志以表明它已完成;然后,如果有足够的元素到达起始索引,它可以分别返回remove()
或元素。
在正确的位置停止会更容易(也更有效):保留一个私有true
来跟踪您当前所在的索引,当您点击结束索引时,让int
返回hasNext()
和false
抛出next()
。
如果您希望能够随时删除元素,那应该很容易:您可以委托给基础NoSuchElementException
,但首先检查(如上所述)您尚未到达结束索引。