Given a list of objects, return an iterator for such a list. Looking for code-review, optimizations and best practices. Verifying complexity to be O(n) where n is sum of all objects, including elements of collections if contained. previously solved here.
public class FlattenIterator implements Iterator<Object> {
private final Stack<Iterator<?>> iteratorStack;
private Object next;
public FlattenIterator(Iterable<?> list) {
if (list == null) {
throw new NullPointerException();
}
iteratorStack = new Stack<Iterator<?>>();
iteratorStack.push(list.iterator());
}
private void moveToNext() {
while ((next == null) && !iteratorStack.empty()) {
Iterator<?> itr = iteratorStack.peek();
// if iterator is empty, then pop it from stack.
if (!itr.hasNext()) {
iteratorStack.pop();
} else {
final Object next = itr.next();
if (next instanceof Iterable) {
iteratorStack.push(((Iterable<?>) next).iterator());
moveToNext();
} else {
this.next = next;
}
}
}
}
/**
* Returns if there are any objects left to iterate over. This method
* can change the internal state of the object when it is called, but repeated
* calls to it will not have any additional side effects.
*/
public boolean hasNext() {
moveToNext();
return next != null;
}
/**
* Returns the next element in our iteration, throwing a NoSuchElementException
* if none is found.
*/
public Object next() {
moveToNext();
if (next == null) {
throw new NoSuchElementException();
}
Object objectToReturn = next;
next = null;
return objectToReturn;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
public class FlattenIteratorTest {
@Test
public void testIterator() {
/**
* < <1, 2>, <"abc", "xyz"> <<1, 2>, <"abc", "xyz">> , a, 10 >
*/
List<Object> genericList = new ArrayList<Object>();
// integer list
List<Integer> listInteger = new ArrayList<Integer>(Arrays.asList(1, 2));
// string list
List<String> listString = new ArrayList<String>(Arrays.asList("abc", "xyz"));
// nested lists.
List<Object> nestedList = new ArrayList<Object>();
nestedList.add(listInteger);
nestedList.add(listString);
genericList.add(listInteger);
genericList.add(listString);
genericList.add(nestedList);
genericList.add('a');
genericList.add(10);
/**
* A very simple test case.
*/
FlattenIterator fi = new FlattenIterator(genericList);
final List<Object> listExpected = new ArrayList<>(Arrays.asList(1, 2, "abc", "xyz", 1, 2, "abc", "xyz", 'a', 10));
final List<Object> listActual = new ArrayList<>();
while (fi.hasNext()) {
listActual.add(fi.next());
}
assertTrue(listExpected.equals(listActual));
}
@Test
public void testEmpty() {
List<Integer> list = new ArrayList<>();
list.addAll(list);
FlattenIterator fi = new FlattenIterator(list);
assertFalse(fi.hasNext());
}
}
Flatterator
! – David Harkness Jul 9 at 2:19