Add collating, zipping, reversing methods to FluentIterable, add ZippingIterator.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1682121 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
db0582a60e
commit
e57282bd9c
|
@ -18,6 +18,7 @@ package org.apache.commons.collections4;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -151,6 +152,55 @@ public class FluentIterable<E> implements Iterable<E> {
|
||||||
return of(IterableUtils.chainedIterable(iterable, other));
|
return of(IterableUtils.chainedIterable(iterable, other));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new FluentIterable whose iterator will traverse the
|
||||||
|
* elements of the current and provided iterable in natural order.
|
||||||
|
* <p>
|
||||||
|
* Example: natural ordering
|
||||||
|
* <ul>
|
||||||
|
* <li>this contains elements [1, 3, 5, 7]
|
||||||
|
* <li>other contains elements [2, 4, 6, 8]
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* The returned iterable will traverse the elements in the following
|
||||||
|
* order: [1, 2, 3, 4, 5, 6, 7, 8]
|
||||||
|
* <p>
|
||||||
|
* A <code>null</code> iterable will be treated as an empty iterable.
|
||||||
|
*
|
||||||
|
* @param other the other iterable to collate, may be null
|
||||||
|
* @return a new iterable, collating this iterable with the other in natural order
|
||||||
|
* @see {@link org.apache.commons.collections4.iterators.CollatingIterator CollatingIterator}
|
||||||
|
*/
|
||||||
|
public FluentIterable<E> collate(final Iterable<E> other) {
|
||||||
|
return of(IterableUtils.collatedIterable(iterable, other, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new FluentIterable whose iterator will traverse the
|
||||||
|
* elements of the current and provided iterable according to the
|
||||||
|
* ordering defined by an comparator.
|
||||||
|
* <p>
|
||||||
|
* Example: descending order
|
||||||
|
* <ul>
|
||||||
|
* <li>this contains elements [7, 5, 3, 1]
|
||||||
|
* <li>other contains elements [8, 6, 4, 2]
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* The returned iterable will traverse the elements in the following
|
||||||
|
* order: [8, 7, 6, 5, 4, 3, 2, 1]
|
||||||
|
* <p>
|
||||||
|
* A <code>null</code> iterable will be treated as an empty iterable.
|
||||||
|
*
|
||||||
|
* @param other the other iterable to collate, may be null
|
||||||
|
* @param comparator the comparator to define an ordering, may be null,
|
||||||
|
* in which case natural ordering will be used
|
||||||
|
* @return a new iterable, collating this iterable with the other in natural order
|
||||||
|
* @see {@link org.apache.commons.collections4.iterators.CollatingIterator CollatingIterator}
|
||||||
|
*/
|
||||||
|
public FluentIterable<E> collate(final Iterable<E> other, Comparator<? super E> comparator) {
|
||||||
|
return of(IterableUtils.collatedIterable(iterable, other, comparator));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method fully traverses an iterator of this iterable and returns
|
* This method fully traverses an iterator of this iterable and returns
|
||||||
* a new iterable with the same contents, but without any reference
|
* a new iterable with the same contents, but without any reference
|
||||||
|
@ -202,6 +252,16 @@ public class FluentIterable<E> implements Iterable<E> {
|
||||||
return of(IterableUtils.loopingIterable(iterable));
|
return of(IterableUtils.loopingIterable(iterable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new FluentIterable whose iterator will traverse the
|
||||||
|
* elements from this iterable in reverse order.
|
||||||
|
*
|
||||||
|
* @return a new iterable, providing a reversed view of this iterable
|
||||||
|
*/
|
||||||
|
public FluentIterable<E> reverse() {
|
||||||
|
return of(IterableUtils.reversedIterable(iterable));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new FluentIterable whose iterator will skip the first
|
* Returns a new FluentIterable whose iterator will skip the first
|
||||||
* N elements from this iterable.
|
* N elements from this iterable.
|
||||||
|
@ -237,6 +297,35 @@ public class FluentIterable<E> implements Iterable<E> {
|
||||||
return of(IterableUtils.uniqueIterable(iterable));
|
return of(IterableUtils.uniqueIterable(iterable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new FluentIterable whose iterator will traverse
|
||||||
|
* the elements of this iterable and the provided elements in
|
||||||
|
* alternating order.
|
||||||
|
*
|
||||||
|
* @param elements the elements to interleave
|
||||||
|
* @return a new iterable, interleaving this iterable with the elements
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public FluentIterable<E> zip(final E... elements) {
|
||||||
|
return zip(Arrays.asList(elements));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new FluentIterable whose iterator will traverse
|
||||||
|
* the elements of this iterable and the other iterable in
|
||||||
|
* alternating order.
|
||||||
|
*
|
||||||
|
* @param other the other iterable to interleave
|
||||||
|
* @return a new iterable, interleaving this iterable with others
|
||||||
|
*/
|
||||||
|
public FluentIterable<E> zip(final Iterable<E>... others) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Iterable<E>[] iterables = new Iterable[1 + others.length];
|
||||||
|
iterables[0] = iterable;
|
||||||
|
System.arraycopy(others, 0, iterables, 1, others.length);
|
||||||
|
return of(IterableUtils.zippingIterable(iterables));
|
||||||
|
}
|
||||||
|
|
||||||
// convenience methods
|
// convenience methods
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -357,10 +446,10 @@ public class FluentIterable<E> implements Iterable<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list containing all elements of this iterable by traversing
|
* Returns a list containing all elements of this iterable by
|
||||||
* its iterator.
|
* traversing its iterator.
|
||||||
* <p>
|
* <p>
|
||||||
* The returned list is mutable.
|
* The returned list is guaranteed to be mutable.
|
||||||
*
|
*
|
||||||
* @return a list of the iterable contents
|
* @return a list of the iterable contents
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -17,11 +17,14 @@
|
||||||
package org.apache.commons.collections4;
|
package org.apache.commons.collections4;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.collections4.iterators.LazyIteratorChain;
|
import org.apache.commons.collections4.iterators.LazyIteratorChain;
|
||||||
|
import org.apache.commons.collections4.iterators.ReverseListIterator;
|
||||||
import org.apache.commons.collections4.iterators.UniqueFilterIterator;
|
import org.apache.commons.collections4.iterators.UniqueFilterIterator;
|
||||||
|
import org.apache.commons.collections4.iterators.ZippingIterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides utility methods and decorators for {@link Iterable} instances.
|
* Provides utility methods and decorators for {@link Iterable} instances.
|
||||||
|
@ -136,6 +139,37 @@ public class IterableUtils {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Collated
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines the two provided iterables into an ordered iterable using the
|
||||||
|
* provided comparator. If the comparator is null, natural ordering will be
|
||||||
|
* used.
|
||||||
|
* <p>
|
||||||
|
* The returned iterable's iterator supports {@code remove()} when the corresponding
|
||||||
|
* input iterator supports it.
|
||||||
|
*
|
||||||
|
* @param <E> the element type
|
||||||
|
* @param a the first iterable, may be null
|
||||||
|
* @param b the second iterable, may be null
|
||||||
|
* @param comparator the comparator defining an ordering over the elements,
|
||||||
|
* may be null, in which case natural ordering will be used
|
||||||
|
* @return a filtered view on the specified iterable
|
||||||
|
*/
|
||||||
|
public static <E> Iterable<E> collatedIterable(final Iterable<E> a,
|
||||||
|
final Iterable<E> b,
|
||||||
|
final Comparator<? super E> comparator) {
|
||||||
|
return new FluentIterable<E>() {
|
||||||
|
@Override
|
||||||
|
public Iterator<E> iterator() {
|
||||||
|
return IteratorUtils.collatedIterator(comparator,
|
||||||
|
emptyIteratorIfNull(a),
|
||||||
|
emptyIteratorIfNull(b));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Filtered
|
// Filtered
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -151,7 +185,8 @@ public class IterableUtils {
|
||||||
* @return a filtered view on the specified iterable
|
* @return a filtered view on the specified iterable
|
||||||
* @throws NullPointerException if predicate is null
|
* @throws NullPointerException if predicate is null
|
||||||
*/
|
*/
|
||||||
public static <E> Iterable<E> filteredIterable(final Iterable<E> iterable, final Predicate<? super E> predicate) {
|
public static <E> Iterable<E> filteredIterable(final Iterable<E> iterable,
|
||||||
|
final Predicate<? super E> predicate) {
|
||||||
if (predicate == null) {
|
if (predicate == null) {
|
||||||
throw new NullPointerException("predicate must not be null.");
|
throw new NullPointerException("predicate must not be null.");
|
||||||
}
|
}
|
||||||
|
@ -232,6 +267,38 @@ public class IterableUtils {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reversed
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reversed view of the given iterable.
|
||||||
|
* <p>
|
||||||
|
* In case the provided iterable is a {@link List} instance, a
|
||||||
|
* {@link ReverseListIterator} will be used to reverse the traversal
|
||||||
|
* order, otherwise an intermediate {@link List} needs to be
|
||||||
|
* created.
|
||||||
|
* <p>
|
||||||
|
* The returned iterable's iterator supports {@code remove()} if the
|
||||||
|
* provided iterable is a {@link List} instance.
|
||||||
|
*
|
||||||
|
* @param <E> the element type
|
||||||
|
* @param iterable the iterable to use, may be null
|
||||||
|
* @return a reversed view of the specified iterable
|
||||||
|
* @see ReverseListIterator
|
||||||
|
*/
|
||||||
|
public static <E> Iterable<E> reversedIterable(final Iterable<E> iterable) {
|
||||||
|
return new FluentIterable<E>() {
|
||||||
|
@Override
|
||||||
|
public Iterator<E> iterator() {
|
||||||
|
final List<E> list = (iterable instanceof List<?>) ?
|
||||||
|
(List<E>) iterable :
|
||||||
|
IteratorUtils.toList(emptyIteratorIfNull(iterable));
|
||||||
|
|
||||||
|
return new ReverseListIterator<E>(list);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Skipping
|
// Skipping
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -276,7 +343,8 @@ public class IterableUtils {
|
||||||
* @return a transformed view of the specified iterable
|
* @return a transformed view of the specified iterable
|
||||||
* @throws NullPointerException if transformer is null
|
* @throws NullPointerException if transformer is null
|
||||||
*/
|
*/
|
||||||
public static <I, O> Iterable<O> transformedIterable(final Iterable<I> iterable, final Transformer<? super I, ? extends O> transformer) {
|
public static <I, O> Iterable<O> transformedIterable(final Iterable<I> iterable,
|
||||||
|
final Transformer<? super I, ? extends O> transformer) {
|
||||||
if (transformer == null) {
|
if (transformer == null) {
|
||||||
throw new NullPointerException("transformer must not be null.");
|
throw new NullPointerException("transformer must not be null.");
|
||||||
}
|
}
|
||||||
|
@ -310,6 +378,58 @@ public class IterableUtils {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Zipping
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interleaves two iterables into a single iterable.
|
||||||
|
* <p>
|
||||||
|
* The returned iterable has an iterator that traverses the elements in {@code a}
|
||||||
|
* and {@code b} in alternating order. The source iterators are not polled until
|
||||||
|
* necessary.
|
||||||
|
* <p>
|
||||||
|
* The returned iterable's iterator supports {@code remove()} when the corresponding
|
||||||
|
* input iterator supports it.
|
||||||
|
*
|
||||||
|
* @param <E> the element type
|
||||||
|
* @param a the first iterable
|
||||||
|
* @param b the second iterable
|
||||||
|
* @return a new iterable, interleaving the provided iterables
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <E> Iterable<E> zippingIterable(final Iterable<E> a, final Iterable<E> b) {
|
||||||
|
return zippingIterable(new Iterable[] {a, b});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interleaves two iterables into a single iterable.
|
||||||
|
* <p>
|
||||||
|
* The returned iterable has an iterator that traverses the elements in {@code a}
|
||||||
|
* and {@code b} in alternating order. The source iterators are not polled until
|
||||||
|
* necessary.
|
||||||
|
* <p>
|
||||||
|
* The returned iterable's iterator supports {@code remove()} when the corresponding
|
||||||
|
* input iterator supports it.
|
||||||
|
*
|
||||||
|
* @param <E> the element type
|
||||||
|
* @param a the first iterable
|
||||||
|
* @param b the second iterable
|
||||||
|
* @return a new iterable, interleaving the provided iterables
|
||||||
|
*/
|
||||||
|
public static <E> Iterable<E> zippingIterable(final Iterable<E>... iterables) {
|
||||||
|
return new FluentIterable<E>() {
|
||||||
|
@Override
|
||||||
|
public Iterator<E> iterator() {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Iterator<E>[] iterators = new Iterator[iterables.length];
|
||||||
|
for (int i = 0; i < iterables.length; i++) {
|
||||||
|
iterators[i] = emptyIteratorIfNull(iterables[i]);
|
||||||
|
}
|
||||||
|
return new ZippingIterator<E>(iterators);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Utility methods
|
// Utility methods
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.commons.collections4.iterators;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.FluentIterable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides an interleaved iteration over the elements contained in a
|
||||||
|
* collection of Iterators.
|
||||||
|
* <p>
|
||||||
|
* Given two {@link Iterator} instances <code>A</code> and
|
||||||
|
* <code>B</code>, the {@link #next} method on this iterator will
|
||||||
|
* alternate between <code>A.next()</code> and <code>B.next()</code>.
|
||||||
|
*
|
||||||
|
* @since 4.1
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class ZippingIterator<E> implements Iterator<E> {
|
||||||
|
|
||||||
|
/** The {@link Iterator}s to evaluate. */
|
||||||
|
private final Iterator<Iterator<? extends E>> iterators;
|
||||||
|
/** The next iterator to use for next(). */
|
||||||
|
private Iterator<? extends E> nextIterator = null;
|
||||||
|
/** The last iterator which was used for next(). */
|
||||||
|
private Iterator<? extends E> lastReturned = null;
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new <code>ZippingIterator</code> that will provide
|
||||||
|
* interleaved iteration over the two given iterators.
|
||||||
|
*
|
||||||
|
* @param a the first child iterator
|
||||||
|
* @param b the second child iterator
|
||||||
|
* @throws NullPointerException if either iterator is null
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public ZippingIterator(final Iterator<? extends E> a, final Iterator<? extends E> b) {
|
||||||
|
this(new Iterator[] {a, b});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new <code>ZippingIterator</code> that will use the
|
||||||
|
* specified comparator to provide ordered iteration over the array of
|
||||||
|
* iterators.
|
||||||
|
*
|
||||||
|
* @param iterators the array of iterators
|
||||||
|
* @throws NullPointerException if iterators array is or contains null
|
||||||
|
*/
|
||||||
|
public ZippingIterator(final Iterator<? extends E>... iterators) {
|
||||||
|
// create a mutable list
|
||||||
|
final List<Iterator<? extends E>> list = new ArrayList<Iterator<? extends E>>();
|
||||||
|
for (Iterator<? extends E> iterator : iterators) {
|
||||||
|
if (iterator == null) {
|
||||||
|
throw new NullPointerException("Iterator must not be null");
|
||||||
|
}
|
||||||
|
list.add(iterator);
|
||||||
|
}
|
||||||
|
this.iterators = FluentIterable.of(list).loop().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterator Methods
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns <code>true</code> if any child iterator has remaining elements.
|
||||||
|
*
|
||||||
|
* @return true if this iterator has remaining elements
|
||||||
|
*/
|
||||||
|
public boolean hasNext() {
|
||||||
|
// the next iterator has already been determined
|
||||||
|
// this might happen if hasNext() was called multiple
|
||||||
|
if (nextIterator != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(iterators.hasNext()) {
|
||||||
|
final Iterator<? extends E> iterator = iterators.next();
|
||||||
|
if (iterator.hasNext()) {
|
||||||
|
nextIterator = iterator;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// iterator is exhausted, remove it
|
||||||
|
iterators.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the next element from a child iterator.
|
||||||
|
*
|
||||||
|
* @return the next interleaved element
|
||||||
|
* @throws NoSuchElementException if no child iterator has any more elements
|
||||||
|
*/
|
||||||
|
public E next() throws NoSuchElementException {
|
||||||
|
if (!hasNext()) {
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
final E val = nextIterator.next();
|
||||||
|
lastReturned = nextIterator;
|
||||||
|
nextIterator = null;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the last returned element from the child iterator that produced it.
|
||||||
|
*
|
||||||
|
* @throws IllegalStateException if there is no last returned element, or if
|
||||||
|
* the last returned element has already been removed
|
||||||
|
*/
|
||||||
|
public void remove() {
|
||||||
|
if (lastReturned == null) {
|
||||||
|
throw new IllegalStateException("No value can be removed at present");
|
||||||
|
}
|
||||||
|
lastReturned.remove();
|
||||||
|
lastReturned = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue