FluentIterator implements ImmutableIterator<T> { public <K> FluentIterator<List<T>> groupBy(Function<T, K> key) { return fluent(Iterators.groupBy(this, key)); } FluentIterator(Iterator<T> t); static FluentIterator<T> fluent(Iterator<T> t); @Override boolean hasNext(); @Override T next(); boolean weakEquals(Iterator<T> s, int n); @SuppressWarnings("unchecked") FluentIterator<T> filter(Predicate<? super T> p); boolean any(Predicate<? super T> p); boolean all(Predicate<? super T> p); @SuppressWarnings("unchecked") FluentIterator<T> concat(Iterator... ts); FluentIterator<T> peek(Consumer<? super T> cs); List<T> take(int n); List<T> takeAll(); FluentIterator<T> limit(int n); List<FluentIterator<T>> tee(int n); FluentIterator<Pair<T, S>> zip(Iterator<S> s, boolean weak); FluentIterator<List<T>> groupBy(Function<T, K> key); FluentIterator<List<T>> groupBy(); FluentIterator<T> skipDuplicates(Function<T, K> key); FluentIterator<T> skipDuplicates(); FluentIterator<T> keepFirst(Function<? super T, ? extends K> key); FluentIterator<T> keepLast(Function<? super T, ? extends K> key); FluentIterator<V> map(Function<T, V> f); FluentIterator<T> map(Iterator<T> t, BinaryOperator<T> f); T reduce(BinaryOperator<T> f); V reduce(BiFunction<V, T, V> f, V start);  }
@Test public void testGroupBy() { FluentIterator<Integer> s = fluent(empty()); FluentIterator<Integer> t = s.concat(repeat(17, 100), repeat(27, 100)); BinaryOperator<Integer> f = (a, b) -> a + b; int sum = t.groupBy(x -> x % 6).map(List::size).reduce(f); assertEquals(200, sum); t = fluent(unaryGenerator(0, x -> x + 1)); sum = t.groupBy() .map(List::size) .limit(10) .reduce(f); assertEquals(10, sum); t = fluent(empty()); Iterator<List<Integer>> g = groupBy(t); assertFalse(g.hasNext()); s = fluent(unaryGenerator(0, x -> x + 1)).limit(20); t = fluent(repeat(1, 0)).concat(repeat(2000, 10), repeat(3000, 10)); List<List<Pair<Integer, Integer>>> ps = s.zip(t, true).groupBy(Pair::getSecond).takeAll(); assertEquals(2, ps.size()); }