Add unit test for ZippingIterator, add factory methods to IteratorUtils, add changelog entry.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1682196 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c193f6556f
commit
b1e21c8a6e
|
@ -27,6 +27,9 @@
|
|||
Iterable instances. Additionally various supporting methods have been
|
||||
added to "IterableUtils" and "IteratorUtils".
|
||||
</action>
|
||||
<action issue="COLLECTIONS-464" dev="tn" type="add">
|
||||
Added new "ZippingIterator" and factory methods "IteratorUtils#zippingIterator(...)".
|
||||
</action>
|
||||
<action issue="COLLECTIONS-464" dev="tn" type="add">
|
||||
Added new decorator "SkippingIterator" and factory methods "IteratorUtils#skippingIterator(...)".
|
||||
</action>
|
||||
|
|
|
@ -61,6 +61,7 @@ import org.apache.commons.collections4.iterators.TransformIterator;
|
|||
import org.apache.commons.collections4.iterators.UnmodifiableIterator;
|
||||
import org.apache.commons.collections4.iterators.UnmodifiableListIterator;
|
||||
import org.apache.commons.collections4.iterators.UnmodifiableMapIterator;
|
||||
import org.apache.commons.collections4.iterators.ZippingIterator;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
|
@ -489,22 +490,6 @@ public class IteratorUtils {
|
|||
return new BoundedIterator<E>(iterator, offset, max);
|
||||
}
|
||||
|
||||
// Skipping
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Decorates the specified iterator to skip the first N elements.
|
||||
*
|
||||
* @param <E> the element type
|
||||
* @param iterator the iterator to decorate
|
||||
* @param offset the first number of elements to skip
|
||||
* @return a new skipping iterator
|
||||
* @throws IllegalArgumentException if the iterator is null or offset is negative
|
||||
* @since 4.1
|
||||
*/
|
||||
public static <E> SkippingIterator<E> skippingIterator(final Iterator<E> iterator, long offset) {
|
||||
return new SkippingIterator<E>(iterator, offset);
|
||||
}
|
||||
|
||||
// Unmodifiable
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
|
@ -914,6 +899,68 @@ public class IteratorUtils {
|
|||
return PushbackIterator.pushbackIterator(iterator);
|
||||
}
|
||||
|
||||
// Skipping
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Decorates the specified iterator to skip the first N elements.
|
||||
*
|
||||
* @param <E> the element type
|
||||
* @param iterator the iterator to decorate
|
||||
* @param offset the first number of elements to skip
|
||||
* @return a new skipping iterator
|
||||
* @throws IllegalArgumentException if the iterator is null or offset is negative
|
||||
* @since 4.1
|
||||
*/
|
||||
public static <E> SkippingIterator<E> skippingIterator(final Iterator<E> iterator, long offset) {
|
||||
return new SkippingIterator<E>(iterator, offset);
|
||||
}
|
||||
|
||||
// Zipping
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns an iterator that interleaves elements from the decorated iterators.
|
||||
*
|
||||
* @param <E> the element type
|
||||
* @param a the first iterator to interleave
|
||||
* @param b the second iterator to interleave
|
||||
* @return an iterator, interleaving the decorated iterators
|
||||
* @throws IllegalArgumentException if any iterator is null
|
||||
* @since 4.1
|
||||
*/
|
||||
public static <E> ZippingIterator<E> zippingIterator(final Iterator<? extends E> a, final Iterator<? extends E> b) {
|
||||
return new ZippingIterator<E>(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator that interleaves elements from the decorated iterators.
|
||||
*
|
||||
* @param <E> the element type
|
||||
* @param a the first iterator to interleave
|
||||
* @param b the second iterator to interleave
|
||||
* @param c the third iterator to interleave
|
||||
* @return an iterator, interleaving the decorated iterators
|
||||
* @throws IllegalArgumentException if any iterator is null
|
||||
* @since 4.1
|
||||
*/
|
||||
public static <E> ZippingIterator<E> zippingIterator(final Iterator<? extends E> a,
|
||||
final Iterator<? extends E> b,
|
||||
final Iterator<? extends E> c) {
|
||||
return new ZippingIterator<E>(a, b, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator that interleaves elements from the decorated iterators.
|
||||
*
|
||||
* @param <E> the element type
|
||||
* @param iterators the array of iterators to interleave
|
||||
* @return an iterator, interleaving the decorated iterators
|
||||
* @throws IllegalArgumentException if any iterator is null
|
||||
* @since 4.1
|
||||
*/
|
||||
public static <E> ZippingIterator<E> zippingIterator(final Iterator<? extends E>... iterators) {
|
||||
return new ZippingIterator<E>(iterators);
|
||||
}
|
||||
|
||||
// Views
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
|
|
|
@ -27,9 +27,9 @@ 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>.
|
||||
* Given two {@link Iterator} instances {@code A} and {@code B}, the
|
||||
* {@link #next} method on this iterator will switch between {@code A.next()}
|
||||
* and {@code B.next()} until both iterators are exhausted.
|
||||
*
|
||||
* @since 4.1
|
||||
* @version $Id$
|
||||
|
@ -38,8 +38,10 @@ 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;
|
||||
|
||||
|
@ -50,8 +52,8 @@ public class ZippingIterator<E> implements Iterator<E> {
|
|||
* 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
|
||||
* @param a the first child iterator
|
||||
* @param b the second child iterator
|
||||
* @throws NullPointerException if either iterator is null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -60,19 +62,34 @@ public class ZippingIterator<E> implements Iterator<E> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ZippingIterator</code> that will use the
|
||||
* specified comparator to provide ordered iteration over the array of
|
||||
* iterators.
|
||||
* Constructs a new <code>ZippingIterator</code> that will provide
|
||||
* interleaved iteration over the three given iterators.
|
||||
*
|
||||
* @param iterators the array of iterators
|
||||
* @throws NullPointerException if iterators array is or contains null
|
||||
* @param a the first child iterator
|
||||
* @param b the second child iterator
|
||||
* @param c the third child iterator
|
||||
* @throws NullPointerException if either iterator is null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public ZippingIterator(final Iterator<? extends E> a,
|
||||
final Iterator<? extends E> b,
|
||||
final Iterator<? extends E> c) {
|
||||
this(new Iterator[] {a, b, c});
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ZippingIterator</code> that will provide
|
||||
* interleaved iteration of the specified iterators.
|
||||
*
|
||||
* @param iterators the array of iterators
|
||||
* @throws NullPointerException if any iterator is null
|
||||
*/
|
||||
public ZippingIterator(final Iterator<? extends E>... iterators) {
|
||||
// create a mutable list
|
||||
// create a mutable list to be able to remove exhausted iterators
|
||||
final List<Iterator<? extends E>> list = new ArrayList<Iterator<? extends E>>();
|
||||
for (Iterator<? extends E> iterator : iterators) {
|
||||
for (final Iterator<? extends E> iterator : iterators) {
|
||||
if (iterator == null) {
|
||||
throw new NullPointerException("Iterator must not be null");
|
||||
throw new NullPointerException("Iterator must not be null.");
|
||||
}
|
||||
list.add(iterator);
|
||||
}
|
||||
|
@ -83,21 +100,21 @@ public class ZippingIterator<E> implements Iterator<E> {
|
|||
// -------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if any child iterator has remaining elements.
|
||||
* Returns {@code true} 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
|
||||
// this might happen if hasNext() is called multiple
|
||||
if (nextIterator != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
while(iterators.hasNext()) {
|
||||
final Iterator<? extends E> iterator = iterators.next();
|
||||
if (iterator.hasNext()) {
|
||||
nextIterator = iterator;
|
||||
final Iterator<? extends E> childIterator = iterators.next();
|
||||
if (childIterator.hasNext()) {
|
||||
nextIterator = childIterator;
|
||||
return true;
|
||||
} else {
|
||||
// iterator is exhausted, remove it
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* 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 org.apache.commons.collections4.IteratorUtils;
|
||||
|
||||
/**
|
||||
* Unit test suite for {@link ZippingIterator}.
|
||||
*
|
||||
* @version $Id$
|
||||
*/
|
||||
@SuppressWarnings("boxing")
|
||||
public class ZippingIteratorTest extends AbstractIteratorTest<Integer> {
|
||||
|
||||
//------------------------------------------------------------ Conventional
|
||||
|
||||
public ZippingIteratorTest(final String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------- Lifecycle
|
||||
|
||||
private ArrayList<Integer> evens = null;
|
||||
private ArrayList<Integer> odds = null;
|
||||
private ArrayList<Integer> fib = null;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
evens = new ArrayList<Integer>();
|
||||
odds = new ArrayList<Integer>();
|
||||
for (int i = 0; i < 20; i++) {
|
||||
if (0 == i % 2) {
|
||||
evens.add(i);
|
||||
} else {
|
||||
odds.add(i);
|
||||
}
|
||||
}
|
||||
fib = new ArrayList<Integer>();
|
||||
fib.add(1);
|
||||
fib.add(1);
|
||||
fib.add(2);
|
||||
fib.add(3);
|
||||
fib.add(5);
|
||||
fib.add(8);
|
||||
fib.add(13);
|
||||
fib.add(21);
|
||||
}
|
||||
|
||||
//---------------------------------------------------- TestIterator Methods
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ZippingIterator<Integer> makeEmptyIterator() {
|
||||
return new ZippingIterator<Integer>(IteratorUtils.<Integer>emptyIterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZippingIterator<Integer> makeObject() {
|
||||
return new ZippingIterator<Integer>(evens.iterator(), odds.iterator(), fib.iterator());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------- Tests
|
||||
|
||||
public void testIterateEven() {
|
||||
@SuppressWarnings("unchecked")
|
||||
final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(evens.iterator());
|
||||
for (int i = 0; i < evens.size(); i++) {
|
||||
assertTrue(iter.hasNext());
|
||||
assertEquals(evens.get(i), iter.next());
|
||||
}
|
||||
assertTrue(!iter.hasNext());
|
||||
}
|
||||
|
||||
public void testIterateEvenOdd() {
|
||||
final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(evens.iterator(), odds.iterator());
|
||||
for (int i = 0; i < 20; i++) {
|
||||
assertTrue(iter.hasNext());
|
||||
assertEquals(Integer.valueOf(i), iter.next());
|
||||
}
|
||||
assertTrue(!iter.hasNext());
|
||||
}
|
||||
|
||||
public void testIterateOddEven() {
|
||||
final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(odds.iterator(), evens.iterator());
|
||||
for (int i = 0, j = 0; i < 20; i++) {
|
||||
assertTrue(iter.hasNext());
|
||||
int val = iter.next();
|
||||
if (i % 2 == 0) {
|
||||
assertEquals(odds.get(j).intValue(), val);
|
||||
} else {
|
||||
assertEquals(evens.get(j).intValue(), val);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
assertTrue(!iter.hasNext());
|
||||
}
|
||||
|
||||
public void testIterateEvenEven() {
|
||||
final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(evens.iterator(), evens.iterator());
|
||||
for (int i = 0; i < evens.size(); i++) {
|
||||
assertTrue(iter.hasNext());
|
||||
assertEquals(evens.get(i), iter.next());
|
||||
assertTrue(iter.hasNext());
|
||||
assertEquals(evens.get(i), iter.next());
|
||||
}
|
||||
assertTrue(!iter.hasNext());
|
||||
}
|
||||
|
||||
public void testIterateFibEvenOdd() {
|
||||
final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(fib.iterator(), evens.iterator(), odds.iterator());
|
||||
|
||||
assertEquals(Integer.valueOf(1),iter.next()); // fib 1
|
||||
assertEquals(Integer.valueOf(0),iter.next()); // even 0
|
||||
assertEquals(Integer.valueOf(1),iter.next()); // odd 1
|
||||
assertEquals(Integer.valueOf(1),iter.next()); // fib 1
|
||||
assertEquals(Integer.valueOf(2),iter.next()); // even 2
|
||||
assertEquals(Integer.valueOf(3),iter.next()); // odd 3
|
||||
assertEquals(Integer.valueOf(2),iter.next()); // fib 2
|
||||
assertEquals(Integer.valueOf(4),iter.next()); // even 4
|
||||
assertEquals(Integer.valueOf(5),iter.next()); // odd 5
|
||||
assertEquals(Integer.valueOf(3),iter.next()); // fib 3
|
||||
assertEquals(Integer.valueOf(6),iter.next()); // even 6
|
||||
assertEquals(Integer.valueOf(7),iter.next()); // odd 7
|
||||
assertEquals(Integer.valueOf(5),iter.next()); // fib 5
|
||||
assertEquals(Integer.valueOf(8),iter.next()); // even 8
|
||||
assertEquals(Integer.valueOf(9),iter.next()); // odd 9
|
||||
assertEquals(Integer.valueOf(8),iter.next()); // fib 8
|
||||
assertEquals(Integer.valueOf(10),iter.next()); // even 10
|
||||
assertEquals(Integer.valueOf(11),iter.next()); // odd 11
|
||||
assertEquals(Integer.valueOf(13),iter.next()); // fib 13
|
||||
assertEquals(Integer.valueOf(12),iter.next()); // even 12
|
||||
assertEquals(Integer.valueOf(13),iter.next()); // odd 13
|
||||
assertEquals(Integer.valueOf(21),iter.next()); // fib 21
|
||||
assertEquals(Integer.valueOf(14),iter.next()); // even 14
|
||||
assertEquals(Integer.valueOf(15),iter.next()); // odd 15
|
||||
assertEquals(Integer.valueOf(16),iter.next()); // even 16
|
||||
assertEquals(Integer.valueOf(17),iter.next()); // odd 17
|
||||
assertEquals(Integer.valueOf(18),iter.next()); // even 18
|
||||
assertEquals(Integer.valueOf(19),iter.next()); // odd 19
|
||||
|
||||
assertTrue(!iter.hasNext());
|
||||
}
|
||||
|
||||
public void testRemoveFromSingle() {
|
||||
@SuppressWarnings("unchecked")
|
||||
final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(evens.iterator());
|
||||
int expectedSize = evens.size();
|
||||
while (iter.hasNext()) {
|
||||
final Object o = iter.next();
|
||||
final Integer val = (Integer) o;
|
||||
if (val.intValue() % 4 == 0) {
|
||||
expectedSize--;
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
assertEquals(expectedSize, evens.size());
|
||||
}
|
||||
|
||||
public void testRemoveFromDouble() {
|
||||
final ZippingIterator<Integer> iter = new ZippingIterator<Integer>(evens.iterator(), odds.iterator());
|
||||
int expectedSize = evens.size() + odds.size();
|
||||
while (iter.hasNext()) {
|
||||
final Object o = iter.next();
|
||||
final Integer val = (Integer) o;
|
||||
if (val.intValue() % 4 == 0 || val.intValue() % 3 == 0) {
|
||||
expectedSize--;
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
assertEquals(expectedSize, evens.size() + odds.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue