Interview: Design an iterator for a collection of collections - java

Design an iterator for a collection of collections in java. The iterator should hide the nesting, allowing you to iterate all of the elements belonging to all of the collections as if you were working with a single collection

This is an old question, but nowadays (2019) we have JDK8+ goodies. In particular, we have streams, which make this task straightforward:
public static <T> Iterator<T> flatIterator(Collection<Collection<T>> collections) {
return collections.stream()
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.iterator();
}
I'm filtering null inner collections out, just in case...
EDIT: If you also want to filter null elements out of the inner collections, just add an extra non-null filter aflter flatMap:
return collections.stream()
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.filter(Objects::nonNull)
.iterator();

Here is a possible implementation. Note that I left remove() unimplemented:
public class MultiIterator <T> implements Iterator<T>{
private Iterator<? extends Collection<T>> it;
private Iterator<T> innerIt;
private T next;
private boolean hasNext = true;
public MultiIterator(Collection<? extends Collection<T>> collections) {
it = collections.iterator();
prepareNext();
}
private void prepareNext() {
do {
if (innerIt == null || !innerIt.hasNext()) {
if (!it.hasNext()) {
hasNext = false;
return;
} else
innerIt = it.next().iterator();
}
} while (!innerIt.hasNext());
next = innerIt.next();
}
#Override
public boolean hasNext() {
return hasNext;
}
#Override
public T next() {
if (!hasNext)
throw new NoSuchElementException();
T res = next;
prepareNext();
return res;
}
#Override
public void remove() {
//TODO
}
}

In this post you can see two implementations, the only (minor) difference is that it takes an iterator of iterators instead of a collection of collections.
This difference combined with the requirement to iterate the elements in a round-robin fashion (a requirement that wasn't requested by the OP in this question) adds the overhead of copying the iterators into a list.
The first approach is lazy: it will iterate an element only when this element is requested, the 'price' we have to pay is that the code is more complex because it needs to handle more edge-cases:
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
public class MultiIterator<E> implements Iterator {
List<Iterator<E>> iterators = new LinkedList<>();
Iterator<E> current = null;
public MultiIterator(Iterator<Iterator<E>> iterator) {
// copy the iterators into a list
while (iterator.hasNext()) {
iterators.add(iterator.next());
}
}
#Override
public boolean hasNext() {
boolean result = false;
if (iterators.isEmpty() && (current == null || !current.hasNext())) {
return false;
}
if (current == null) {
current = iterators.remove(0);
}
while (!current.hasNext() && !iterators.isEmpty()) {
current = iterators.remove(0);
}
if (current.hasNext()) {
result = true;
}
return result;
}
#Override
public E next() {
if (current == null) {
try {
current = iterators.remove(0);
} catch (IndexOutOfBoundsException e) {
throw new NoSuchElementException();
}
}
E result = current.next(); // if this method was called without checking 'hasNext' this line might raise NoSuchElementException which is fine
iterators.add(current);
current = iterators.remove(0);
return result;
}
// test
public static void main(String[] args) {
List<Integer> a = new LinkedList<>();
a.add(1);
a.add(7);
a.add(13);
a.add(17);
List<Integer> b = new LinkedList<>();
b.add(2);
b.add(8);
b.add(14);
b.add(18);
List<Integer> c = new LinkedList<>();
c.add(3);
c.add(9);
List<Integer> d = new LinkedList<>();
d.add(4);
d.add(10);
d.add(15);
List<Integer> e = new LinkedList<>();
e.add(5);
e.add(11);
List<Integer> f = new LinkedList<>();
f.add(6);
f.add(12);
f.add(16);
f.add(19);
List<Iterator<Integer>> iterators = new LinkedList<>();
iterators.add(a.iterator());
iterators.add(b.iterator());
iterators.add(c.iterator());
iterators.add(d.iterator());
iterators.add(e.iterator());
iterators.add(f.iterator());
MultiIterator<Integer> it = new MultiIterator<>(iterators.iterator());
while (it.hasNext()) {
System.out.print(it.next() + ","); // prints: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,
}
}
}
and the second ('greedy' copying of all the elements from all the iterators in the requested order into a list and returning an iterator to that list ):
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class MultiIterator<E> {
Iterator<Iterator<E>> iterator = null;
List<E> elements = new LinkedList<>();
private MultiIterator(Iterator<Iterator<E>> iterator) {
this.iterator = iterator;
}
private void copyElementsInOrder() {
List<Iterator<E>> iterators = new LinkedList<>();
// copy the iterators into a list
while (iterator.hasNext()) {
iterators.add(iterator.next());
}
// go over the list, round-robin, and grab one
// element from each sub-iterator and add it to *elements*
// empty sub-iterators will get dropped off the list
while (!iterators.isEmpty()) {
Iterator<E> subIterator = iterators.remove(0);
if (subIterator.hasNext()) {
elements.add(subIterator.next());
iterators.add(subIterator);
}
}
}
public static <E> Iterator<E> iterator(Iterator<Iterator<E>> iterator) {
MultiIterator<E> instance = new MultiIterator<>(iterator);
instance.copyElementsInOrder();
return instance.elements.iterator();
}
// test
public static void main(String[] args) {
List<Integer> a = new LinkedList<>();
a.add(1);
a.add(7);
a.add(13);
a.add(17);
List<Integer> b = new LinkedList<>();
b.add(2);
b.add(8);
b.add(14);
b.add(18);
List<Integer> c = new LinkedList<>();
c.add(3);
c.add(9);
List<Integer> d = new LinkedList<>();
d.add(4);
d.add(10);
d.add(15);
List<Integer> e = new LinkedList<>();
e.add(5);
e.add(11);
List<Integer> f = new LinkedList<>();
f.add(6);
f.add(12);
f.add(16);
f.add(19);
List<Iterator<Integer>> iterators = new LinkedList<>();
iterators.add(a.iterator());
iterators.add(b.iterator());
iterators.add(c.iterator());
iterators.add(d.iterator());
iterators.add(e.iterator());
iterators.add(f.iterator());
Iterator<Integer> it = MultiIterator.<Integer>iterator(iterators.iterator());
while (it.hasNext()) {
System.out.print(it.next() + ","); // prints: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,
}
}
}
I included a simple 'test' code in order to show the way to use the MultiIterator, this is not always trivial (because of the use of Generics) as you can see on the line:
Iterator<Integer> it = MultiIterator.<Integer>iterator(iterators.iterator());

Here is another implementation:
import java.util.Iterator;
import java.util.NoSuchElementException;
import static java.util.Collections.emptyIterator;
public class Multiterator<E> implements Iterator<E> {
private Iterator<Iterator<E>> root;
private Iterator<E> current;
public Multiterator(Iterator<Iterator<E>> root) {
this.root = root;
current = null;
}
#Override
public boolean hasNext() {
if (current == null || !current.hasNext()) {
current = getNextNonNullOrEmpty(root);
}
return current.hasNext();
}
private Iterator<E> getNextNonNullOrEmpty(Iterator<Iterator<E>> root) {
while (root.hasNext()) {
Iterator<E> next = root.next();
if (next != null && next.hasNext()) {
return next;
}
}
return emptyIterator();
}
#Override
public E next() {
if (current == null) {
throw new NoSuchElementException();
}
return current.next();
}
}

First, take a look at the implementation of the iterator in java.util.LinkedList
http://www.docjar.com/html/api/java/util/LinkedList.java.html
From there your task is easy just implement a single iterator that takes into account the fact that it is iterating over collections.
Regards.

if all you have to work with is the java Iterator: which just have hasNext(), next() and remove(), i figured you have to go around it.
Process it as you will process a 2D array, that is, with an outer and inner loop, because they have same "arrangement" but different datatype. As you process, you transfer them to a new collection.
so maybe a private method:
private void convertToSingleCollection()
{
while("column")
{
//convert the "column" to an arra
for( "Row")
{
//add to newCollection here
}
//remove the processed column from CollectionOFcollection
}
}
//call the above method in your constructor
public iterator<T> Iterator()
{
newCollection.iterator();
}
public boolean hasNext()
{
return Iterator().hasNext()
}
public T next()
{
if(!hasNext())
{
//exception message or message
}
else
//return "next"
}
end
I hope this helps. There should be other ways to solve it i guess.

Related

Java Implementation of T first() method to class Hashset<T>

I am having difficulty with the following exercise. I do not know which way to approach it. I know I should use some sort of iteration but I am unsure. I have been able to implement the T first() method with a binary search tree but not with a HashSet.
Add the following method to class HashSet<T> and write a suitable test program.
T first()
// least value in the set (if the set is empty
// throws NoSuchElementException)
import java.util.*;
import java.lang.Iterable;
class HashSet<T extends Comparable<T>> implements Iterable<T> {
private LinkedSet<T>[] hashTable; // hash table
HashSet() { // create the empty set
hashTable = (LinkedSet<T>[])(new LinkedSet[1000]);
// note coding trick!
for (int i=0; i<hashTable.length; i++)
hashTable[i] = new LinkedSet<T>();
//Exercise 1
int numItems = 0;
for (LinkedSet<T> miniSet: hashTable)
numItems = numItems+miniSet.size();
}
private int hash(T t) { // hash t into hashTable index
return Math.abs(t.hashCode()%hashTable.length);
}
int size() {
int numItems = 0;
for (LinkedSet<T> miniSet: hashTable)
numItems = numItems+miniSet.size();
return numItems;
}
boolean contains(T t) {
return hashTable[hash(t)].contains(t);
}
boolean add(T t) {
return hashTable[hash(t)].add(t);
}
boolean remove(T t) {
return hashTable[hash(t)].remove(t);
}
//Exercise 3
public Iterator<T> iterator() {
ArrayList<T> items = new ArrayList<T>();
for (LinkedSet<T> ls: hashTable)
for (T t: ls) items.add(t);
return items.iterator();
}
boolean addAll(HashSet<T> ts){
boolean changed = false;
for(T i : ts)
if(add(i))
changed =true;
return true;
// add all elements of ts to set; ts is unchanged.
}
}
import java.util.Iterator;
public class Prog {
public static <T extends Comparable<T>> T first(HashSet<T> hs)
// least value in the set (if the set is empty
// throws NoSuchElementException
{
T least = null;
for(T i : hs){
if (i.compareTo(least)<0){
i = least;
}
}
return least;
}
import java.util.List;
public class main1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
HashSet<String> test1 = new HashSet<String>();
test1.add("sean");
test1.add("adam");
test1.add("ava");
HashSet<Integer> test2 = new HashSet<Integer>();
test2.add(2);
test2.add(10);
test2.add(5);
System.out.println(test1.size());
System.out.println(Prog.first(test2));
}
}
You can:
iterate through values: try for ( T x: the_set) ...
take the min: take the first, an iterate, and if new is less, take it
return that value (or exception if no value)
try to complete this
public static <T> T first(HashSet<T> _ht)
{
// if _ht empty throws an exception
// TODO
// Take the first (or any element)
// TODO
T least;
for (T one_element: _ht)
{
// compare one_element and least
// TODO
// and keep the least !
}
return least;
}
I agree with the comment from Peter, a HashSet has no concept of "first" or "last", since it's not ordered. However, there is the class TreeSet, which implements SortedSet.
The element type must define a natural order (e.g. int, or Comparable<T>), or otherwise you have to provide a Comparator<T> to the constructor of the tree set.
Example:
Integer[] numbers = { 5, 9, 1, 11 };
TreeSet<Integer> set = new TreeSet<>(Arrays.asList(numbers));
Integer least = set.first(); // 1
One possible implementation of the first() method (assuming a binary tree):
public T first() {
Node<T> p = root;
if (p != null) {
while (p.left != null) { // not "while (p != null)"
p = p.left;
}
}
return p == null ? null : p.item;
}

java iterator with index parameter

hi a normal iterator for a LinkedList would be the following, however, how do we build an iterator that returns an iterator starting at a specified index? How do we build:
public Iterator<E>iterator(int index)???
thanks!
normal Iterator:
public Iterator<E> iterator( )
{
return new ListIterator();
}
private class ListIterator implements Iterator<E>
{
private Node current;
public ListIterator()
{
current = head; // head in the enclosing list
}
public boolean hasNext()
{
return current != null;
}
public E next()
{
E ret = current.item;
current = current.next;
return ret;
}
public void remove() { /* omitted because optional */ }
}
Well you could just call the normal iterator() method, then call next() that many times:
public Iterator<E> iterator(int index) {
Iterator<E> iterator = iterator();
for (int i = 0; i < index && iterator.hasNext(); i++) {
iterator.next();
}
return iterator;
}
This is kick-off example how to implement such iterator, but it's advised also to create or extend appropriate interface and make this object implementing this interface for convention.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IterableObject {
private List<String> values = new ArrayList<String>();
public Iterator<String> getIterator(final int index) {
Iterator<String> it = new Iterator<String>() {
private int current = index;
#Override
public void remove() {
// TODO Auto-generated method stub
}
#Override
public String next() {
String value = values.get(current);
current++;
return value;
}
#Override
public boolean hasNext() {
if(values.size() > current){
return true;
}else{
return false;
}
}
};
return it;
}
}
UPDATE
According to comments I've written an Iterator for LinkedList
public Iterator<String> getIterator(final int index) {
Iterator<String> it = new Iterator<String>() {
private Object currentObject = null;
{
/*initialize block where we traverse linked list
that it will pointed to object at place index*/
System.out.println("initialize" + currentWord);
for(int i = 0; currentObject.next != null && i < index; i++, currentObject = currentObject.next)
;
}
#Override
public void remove() {
// TODO Auto-generated method stub
}
#Override
public String next() {
Object obj = currentObject.next;
currentObject = currentObject.next;
return obj;
}
#Override
public boolean hasNext() {
return currentObject.next != null;
}
};
return it;
}
Because Iterator is object of Anonymous class we can't use constructor but can initialise it in initialise block look at this answer: https://stackoverflow.com/a/362463/947111 We traverse it once at the beginning (sorry for C style) so it will point to currentObject. All remain code is self explained.

How to implement iterator on nested collection in Java?

I have a nested collection with this representation Collection<Collection<T>>. I have implemented the Iterator on the class, but the next() method is not giving the right results. It is fetching only the first element of each list. Example List<List<String>> and values are {"1","2"},{"3","4"},{"5","6"}. The Complete layout of class.
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
public class NestedCollectionIterator implements Iterator<Object> {
private Collection<? extends Collection<? extends Object>> _collOfColl = null;
private Iterator<? extends Collection<? extends Object>> itCollection = null;
private Iterator<? extends Object> innerIterator = null;
Object next = null;
public NestedCollectionIterator( Collection<? extends Collection<? extends Object>> collofColl){
_collOfColl = collofColl;
itCollection = _collOfColl.iterator();
}
#Override
public boolean hasNext() {
if(itCollection.hasNext()){
innerIterator = itCollection.next().iterator();
if(innerIterator != null || innerIterator.hasNext()){
next = innerIterator.next();
return true;
}
}
return false;
}
public Object next() {
if(hasNext()){
Object obj = next;
//Need some changes here.
return obj;
}
return null;
}
#Override
public void remove() {}
}
Class to test the implementation
class Sample{
public static void main(String[] args){
List<List<String>> Nestedlist = new ArrayList<List<String>>();
List<String> l = new ArrayList<String>();
l.add("1");
l.add("2");
Nestedlist.add(l);
l = new ArrayList<String>();
l.add("3");
l.add("4");
Nestedlist.add(l);
l = new ArrayList<String>();
l.add("5");
l.add("6");
Nestedlist.add(l);
NestedCollectionIterator cc = new NestedCollectionIterator(Nestedlist);
while(cc.hasNext()){
System.out.println(cc.next.toString());
}
}
}
the results is 1,3,5. How make the list iterate over all the elements in list first and then move to next collection item inside it?
Thanks.
This one works for me - it is not generalised to Collection but there are utility methods that can give you an iterator-iterator across up to three levels of Map. I am sure you could adapt it to collections in general.
public class NestedIterator<T> implements Iterator<T> {
// Outer iterator. Goes null when exhausted.
Iterator<Iterator<T>> i2 = null;
// Inner iterator. Goes null when exhausted.
Iterator<T> i1 = null;
// Next value.
T next = null;
// Takes a depth-2 iterator.
public NestedIterator(Iterator<Iterator<T>> i2) {
this.i2 = i2;
// Prime the pump.
if (i2 != null && i2.hasNext()) {
i1 = i2.next();
}
}
#Override
public boolean hasNext() {
// Is there one waiting?
if (next == null) {
// No!
// i1 will go null if it is exhausted.
if (i1 == null) {
// i1 is exhausted! Get a new one from i2.
if (i2 != null && i2.hasNext()) {
/// Get next.
i1 = i2.next();
// Set i2 null if exhausted.
if (!i2.hasNext()) {
// Exhausted.
i2 = null;
}
} else {
// Exhausted.
i2 = null;
}
}
// A null i1 now will mean all is over!
if (i1 != null) {
if (i1.hasNext()) {
// get next.
next = i1.next();
// Set i1 null if exhausted.
if (!i1.hasNext()) {
// Exhausted.
i1 = null;
}
} else {
// Exhausted.
i1 = null;
}
}
}
return next != null;
}
#Override
public T next() {
T n = next;
next = null;
return n;
}
#Override
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
// Iterating across Maps of Maps of Maps.
static <K1, K2, K3, V> Iterator<Iterator<Iterator<V>>> iiiV(Map<K1, Map<K2, Map<K3, V>>> mapMapMap) {
final Iterator<Map<K2, Map<K3, V>>> mmi = iV(mapMapMap);
return new Iterator<Iterator<Iterator<V>>>() {
#Override
public boolean hasNext() {
return mmi.hasNext();
}
#Override
public Iterator<Iterator<V>> next() {
return iiV(mmi.next());
}
#Override
public void remove() {
mmi.remove();
}
};
}
// Iterating across Maps of Maps.
static <K1, K2, V> Iterator<Iterator<V>> iiV(Map<K1, Map<K2, V>> mapMap) {
final Iterator<Map<K2, V>> mi = iV(mapMap);
return new Iterator<Iterator<V>>() {
#Override
public boolean hasNext() {
return mi.hasNext();
}
#Override
public Iterator<V> next() {
return iV(mi.next());
}
#Override
public void remove() {
mi.remove();
}
};
}
// Iterating across Map values.
static <K, V> Iterator<V> iV(final Map<K, V> map) {
return iV(map.entrySet().iterator());
}
// Iterating across Map.Entries.
static <K, V> Iterator<V> iV(final Iterator<Map.Entry<K, V>> mei) {
return new Iterator<V>() {
#Override
public boolean hasNext() {
return mei.hasNext();
}
#Override
public V next() {
return mei.next().getValue();
}
#Override
public void remove() {
mei.remove();
}
};
}
}

Enqueue List method

Is there a way to enqueue this method faster? I'm trying to add performance test to this method and wondering if there is alternative for this.
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
public class ImmutableQueueImpl<E> implements ImmutableQueue<E> {
private List<E> queue;
public ImmutableQueueImpl() {
queue = new ArrayList<E>();
}
private ImmutableQueueImpl(List<E> queue) {
this.queue = queue; }
#Override
public ImmutableQueue<E> enqueue(E e) {
if (e == null) {
throw new IllegalArgumentException();
}
List<E> clone = new ArrayList<E>(queue); clone.add(e);
return new ImmutableQueueImpl<E>(clone);
}
#Override
public ImmutableQueue<E> dequeue() {
if (queue.isEmpty()) {
throw new NoSuchElementException();
}
List<E> clone = new ArrayList<E>(queue);
clone.remove(0);
return new ImmutableQueueImpl<E>(clone);
}
#Override
public E peek() {
if (queue.isEmpty()) {
throw new NoSuchElementException();
}
return queue.get(0);
}
#Override
public int size() {
return queue.size();
}
}
EDIT
I have added the full code for reference. Hope that helps
It is possible to get O(1) for enqueue/dequeue operations in immutable queue using 2 immutable lists internally.
Here is code borrowed from Scala book:
class Queue[T](
private val leading: List[T],
private val trailing: List[T]
) {
private def mirror =
if (leading.isEmpty) new Queue(trailing.reverse, Nil)
else this
def head = mirror.leading.head
def tail = {
val q = mirror
new Queue(q.leading.tail, q.trailing)
}
def append(x: T) = new Queue(leading, x :: trailing)
}

Can we write our own iterator in Java?

If I have a list containing [alice, bob, abigail, charlie] and I want to write an iterator such that it iterates over elements that begin with 'a', can I write my own ? How can I do that ?
The best reusable option is to implement the interface Iterable and override the method iterator().
Here's an example of a an ArrayList like class implementing the interface, in which you override the method Iterator().
import java.util.Iterator;
public class SOList<Type> implements Iterable<Type> {
private Type[] arrayList;
private int currentSize;
public SOList(Type[] newArray) {
this.arrayList = newArray;
this.currentSize = arrayList.length;
}
#Override
public Iterator<Type> iterator() {
Iterator<Type> it = new Iterator<Type>() {
private int currentIndex = 0;
#Override
public boolean hasNext() {
return currentIndex < currentSize && arrayList[currentIndex] != null;
}
#Override
public Type next() {
return arrayList[currentIndex++];
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return it;
}
}
This class implements the Iterable interface using Generics. Considering you have elements to the array, you will be able to get an instance of an Iterator, which is the needed instance used by the "foreach" loop, for instance.
You can just create an anonymous instance of the iterator without creating extending Iterator and take advantage of the value of currentSize to verify up to where you can navigate over the array (let's say you created an array with capacity of 10, but you have only 2 elements at 0 and 1). The instance will have its owner counter of where it is and all you need to do is to play with hasNext(), which verifies if the current value is not null, and the next(), which will return the instance of your currentIndex. Below is an example of using this API...
public static void main(String[] args) {
// create an array of type Integer
Integer[] numbers = new Integer[]{1, 2, 3, 4, 5};
// create your list and hold the values.
SOList<Integer> stackOverflowList = new SOList<Integer>(numbers);
// Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
for(Integer num : stackOverflowList) {
System.out.print(num);
}
// creating an array of Strings
String[] languages = new String[]{"C", "C++", "Java", "Python", "Scala"};
// create your list and hold the values using the same list implementation.
SOList<String> languagesList = new SOList<String>(languages);
System.out.println("");
// Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
for(String lang : languagesList) {
System.out.println(lang);
}
}
// will print "12345
//C
//C++
//Java
//Python
//Scala
If you want, you can iterate over it as well using the Iterator instance:
// navigating the iterator
while (allNumbers.hasNext()) {
Integer value = allNumbers.next();
if (allNumbers.hasNext()) {
System.out.print(value + ", ");
} else {
System.out.print(value);
}
}
// will print 1, 2, 3, 4, 5
The foreach documentation is located at http://download.oracle.com/javase/1,5.0/docs/guide/language/foreach.html. You can take a look at a more complete implementation at my personal practice google code.
Now, to get the effects of what you need I think you need to plug a concept of a filter in the Iterator... Since the iterator depends on the next values, it would be hard to return true on hasNext(), and then filter the next() implementation with a value that does not start with a char "a" for instance. I think you need to play around with a secondary Interator based on a filtered list with the values with the given filter.
Sure. An iterator is just an implementation of the java.util.Iterator interface. If you're using an existing iterable object (say, a LinkedList) from java.util, you'll need to either subclass it and override its iterator function so that you return your own, or provide a means of wrapping a standard iterator in your special Iterator instance (which has the advantage of being more broadly used), etc.
Good example for Iterable to compute factorial
FactorialIterable fi = new FactorialIterable(10);
Iterator<Integer> iterator = fi.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
Short code for Java 1.8
new FactorialIterable(5).forEach(System.out::println);
Custom Iterable class
public class FactorialIterable implements Iterable<Integer> {
private final FactorialIterator factorialIterator;
public FactorialIterable(Integer value) {
factorialIterator = new FactorialIterator(value);
}
#Override
public Iterator<Integer> iterator() {
return factorialIterator;
}
#Override
public void forEach(Consumer<? super Integer> action) {
Objects.requireNonNull(action);
Integer last = 0;
for (Integer t : this) {
last = t;
}
action.accept(last);
}
}
Custom Iterator class
public class FactorialIterator implements Iterator<Integer> {
private final Integer mNumber;
private Integer mPosition;
private Integer mFactorial;
public FactorialIterator(Integer number) {
this.mNumber = number;
this.mPosition = 1;
this.mFactorial = 1;
}
#Override
public boolean hasNext() {
return mPosition <= mNumber;
}
#Override
public Integer next() {
if (!hasNext())
return 0;
mFactorial = mFactorial * mPosition;
mPosition++;
return mFactorial;
}
}
This is the complete code to write an iterator such that it iterates over elements that begin with 'a':
import java.util.Iterator;
public class AppDemo {
public static void main(String args[]) {
Bag<String> bag1 = new Bag<>();
bag1.add("alice");
bag1.add("bob");
bag1.add("abigail");
bag1.add("charlie");
for (Iterator<String> it1 = bag1.iterator(); it1.hasNext();) {
String s = it1.next();
if (s != null)
System.out.println(s);
}
}
}
Custom Iterator class
import java.util.ArrayList;
import java.util.Iterator;
public class Bag<T> {
private ArrayList<T> data;
public Bag() {
data = new ArrayList<>();
}
public void add(T e) {
data.add(e);
}
public Iterator<T> iterator() {
return new BagIterator();
}
public class BagIterator<T> implements Iterator<T> {
private int index;
private String str;
public BagIterator() {
index = 0;
}
#Override
public boolean hasNext() {
return index < data.size();
}
#Override
public T next() {
str = (String) data.get(index);
if (str.startsWith("a"))
return (T) data.get(index++);
index++;
return null;
}
}
}
You can implement your own Iterator. Your iterator could be constructed to wrap the Iterator returned by the List, or you could keep a cursor and use the List's get(int index) method. You just have to add logic to your Iterator's next method AND the hasNext method to take into account your filtering criteria. You will also have to decide if your iterator will support the remove operation.
Here is the complete answer to the question.
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
class ListIterator implements Iterator<String>{
List<String> list;
int pos = 0;
public ListIterator(List<String> list) {
this.list = list;
}
#Override
public boolean hasNext() {
while(pos < list.size()){
if (list.get(pos).startsWith("a"))
return true;
pos++;
}
return false;
}
#Override
public String next() {
if (hasNext())
return list.get(pos++);
throw new NoSuchElementException();
}
}
public class IteratorTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("alice", "bob", "abigail", "charlie");
ListIterator itr = new ListIterator(list);
while(itr.hasNext())
System.out.println(itr.next()); // prints alice, abigail
}
}
ListIterator is the iterator for the array which returns the elements that start with 'a'.
There is no need for implementing an Iterable interface. But that is a possibility.
There is no need to implement this generically.
It fully satisfies the contract for hasNext() and next(). ie if hasNext() says there are still elements, next() will return those elements. And if hasNext() says no more elements, it returns a valid NoSuchElementException exception.

Categories

Resources