java/guava - 在 iterable/iterator 的某个索引处开始和停止

java/guava - start and stop at certain index of iterable/iterator

我正在寻找一种优雅的方式(可能使用 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),但不是从给定的索引开始。我需要两者的结合。

你会怎么做?

确实没有一种有效的方法来执行此操作,因为迭代器是如此通用。没有什么可以告诉您底层数据结构将有任何方式跳到中间以找到给定的索引。想一想链表:获得索引 k 的唯一方法是遍历链表。

您需要围绕 Iterator 创建一个包装器,并将接口方法委托给底层 Iterator,但向 hasNext() 和 [= 添加一些额外的逻辑13=] 方法,以及 remove() 如果您需要删除支持。第一次调用其中一个时,它将需要遍历底层列表以找到起始索引,并设置一个私有标志以指示它已完成;如果有足够的元素到达起始索引,它可以分别 return true 或元素。

在正确的地方停下来更容易(也更有效):保留一个私有 int 来跟踪您当前所在的索引,当您到达结束索引时,hasNext() return falsenext() 抛出 NoSuchElementException.

如果您希望能够随时删除元素,那应该很简单:您可以委托给底层 remove(),但首先检查(如上所述)您是否没有到达终点指数.

您可以使用 skip 来达到这个目的。

Returns a view of iterable that skips its first numberToSkip elements.

例如,下面将为您提供一个 Iterable,它会跳过前两个元素,然后将其限制为接下来的五个元素:

List<Integer> list = [0, ..., 10];
Iterable<Integer> iterable = Iterables.limit(Iterables.skip(list, 2), 5); //[2, 3, 4, 5, 6]

请注意,参数不被视为 indexes,而是被视为要跳过(或限制)的元素的 number。但是如果知道要跳过多少个元素,就很容易计算结束索引。

 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)


使用 ,您可以使用新的 Stream API,它也有那些 skip 和 limit 方法。

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