I'm working in a school project, where I want to implement the Iterator design pattern. I want to use generic arrays.
Container.java
public interface Container {
Iterator getIterator();
}
Iterator.java
public interface Iterator <T> {
boolean hasNext();
T next();
}
TransactionRepository.java
public class TransactionRepository<T> implements Container {
public TransactionRepository(){
userTransactions = new ArrayList<>();
}
public List<T> userTransactions;
#Override
public Iterator <T> getIterator() {
return new UserTransactions();
}
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
private class UserTransactions implements Iterator <T> {
int index;
#Override
public boolean hasNext() {
return index < userTransactions.size();
}
#Override
public T next() {
if(this.hasNext())
return userTransactions.get(index);
return null;
}
}
}
In my other class, I add the elements to the list by first creating the TransactionRepository object like this: TransactionRepository<String> companyName = new TransactionRepository<String>();.
Then I add elements to the array with the add method companyName.add("CompanyName");. After that I want to print the array using Iterator, but It just won't print the elements. I have tried multiple variations, but none of them worked.
Iterator <String> stringIterator = companyName.getIterator();
while (stringIterator.hasNext()) {
System.out.println("Name : " + companyName.get());
}
With the current implementation List<T> userTransactions is never updated.
In this case userTransactions.size() in hasNext() method will always return 0 so the result of method will be false.
Moreover, you should use stringIterator.next() instead of companyName.get(). Since you implement your own iterator you don't want to use get() method at all.
There is also a need to update index counter variable after calling next() method.
#Override
public T next() {
if (this.hasNext())
return userTransactions.get(index++);
return null;
}
Change modifier on userTransactions to private final as it should be referenced just with iterator.
Code with proposed improvements:
public class TransactionRepository<T> implements Container {
public TransactionRepository() {
userTransactions = new ArrayList<>();
}
public List<T> userTransactions;
#Override
public Iterator<T> getIterator() {
return new UserTransactions();
}
public void add(T t) {
userTransactions.add(t);
}
private class UserTransactions implements Iterator<T> {
int index;
#Override
public boolean hasNext() {
return index < userTransactions.size();
}
#Override
public T next() {
if (this.hasNext()) {
return userTransactions.get(index++);
}
return null;
}
}
}
It seems that you are never adding elements to your userTransactions List on the add method
You add() method doesnt add anything to your list , it's just like a setter of the attribute t , you should use it to add elements to the list instead
public void add(T t) {
userTransactions.add(t);
}
There is also another problem , the index , your next() method gets the index element while you didnt initialise your index variable , i recommand you to do it in this way :
int index = 0 ;
...
public T next() {
if(this.hasNext())
int temp = index;
index++;
return userTransactions.get(temp);
return null;
}
Flatten an iterator of iterators in Java. If the input is [ [1,2], [3,[4,5]], 6], it should return [1,2,3,4,5,6]. Implement hasNext() and next(). Be careful when the inner iterator or list is empty.
I don't think my code works for multiple levels of inner lists.
public class FlattenList {
int index = 0; // keep an index to indicate where the current accessed element is
List<Integer> flattenedList = new ArrayList<>(); // flattenedList
public FlattenList(List<List<Integer>> lists){
for(List<Integer> list : lists){ // add all inner list to our underlying list.
flattenedList.addAll(list);
}
}
public boolean hasNext(){ // check if the index has exceeded the list size
return flattenedList.size() > index? true : false;
}
public Integer next(){ // return the next element, and increment the index
Integer result = flattenedList.get(index);
index++;
return result;
}
}
So basically this is like writing a depth first traversal of a tree. Leaf nodes of this tree are numbers, all interior nodes are modeled as Iterators. Here is some pseudo code:
void flatten(Iterator<Object> iterator, List<Integer> flattenedList) {
for (Object o : iterator) {
if (o instanceof Iterator) {
flatten((Iterator) o, flattenedList);
} else {
flattenedList.add((Integer) o);
}
}
}
Here, I'll start it for you:
public <T> Iterator<T> flatten(final Iterator<Iterator<T>> iterators) {
if (iterators == null) {
throw new IllegalArgumentException("iterators can't be null");
}
return new Iterator<>() {
#Override
public boolean hasNext() {
throw new UnsupportedOperationException("Not implemented: hasNext");
}
#Override
public T next() {
throw new UnsupportedOperationException("Not implemented: next");
}
};
}
Now you just do that pesky brainwork and you'll be done.
EDIT
If you're not used to that syntax, here's a slightly easier one:
public <T> Iterator<T> flatten(final Iterator<Iterator<T>> iterators) {
return new MyFlatteningIterator<>(iterators);
}
public class MyFlatteningIterator<T> implements Iterator<T> {
private final Iterator<Iterator<T>> iterators;
public MyFlatteningIterator(final Iterator<Iterator<T>> iterators) {
if (iterators == null) {
throw new IllegalArgumentException("iterators can't be null");
}
this.iterators = iterators;
}
#Override
public boolean hasNext() {
throw new UnsupportedOperationException("Not implemented: hasNext");
}
#Override
public T next() {
throw new UnsupportedOperationException("Not implemented: next");
}
}
You should not treat this as a list, rather as Jon stated this is more suitable when you are talking about trees. If you infect looking for a solution to get a flatted iterator of list of lists (something that looks like [[1],[1,2,3],[8,9]]) then I think that the following solution will work better
import java.util.Collection;
import java.util.Iterator;
public class FlattedIterator<T> implements Iterator<T> {
private Iterator<T>[] iteratorsArray;
public FlattedIterator(Collection<T>[] items) {
this.iteratorsArray = new Iterator[items.length];
for(int index = 0; index < items.length; index++) {
this.iteratorsArray[index] = items[index].iterator();
}
}
#Override
public boolean hasNext() {
boolean hasNext = false;
for(int index = 0; index < this.iteratorsArray.length; index++) {
hasNext |= this.iteratorsArray[index].hasNext();
}
return hasNext;
}
#Override
public T next() {
int index = 0;
while(index < this.iteratorsArray.length && !this.iteratorsArray[index].hasNext()) {
index++;
}
if(index >= this.iteratorsArray.length ) {
throw new IndexOutOfBoundsException("Reached end of iterator");
}
return this.iteratorsArray[index].next();
}
}
Bear in mind that the reason that I think this solution will work better is due to the fact that in your solution you initialized flattenedList by adding all the data from the given lists meaning that if in some point of the program one of those lists will received more data after you initialized FlattenList then the new data wont appear while you read the iterator.
I'm getting the error "Iterator cannot be resolved to a type". I'm trying to take the storage class and add the code necessary to implement java's Collections class.
I dont think i'm allowed to import Iterator, i think i need to make my own.
public class storage {
private Object[] data = new Object[256];
// Don't allow access to anything not yet stored
private int nextEmptySlot = 0;
private int i=0;
public Object begin(){
return data[0];
}
public Object end(){
return data[nextEmptySlot];
}
//class Iterator() {
// public Storage data;
//}
public Iterator iterator() {
// returns a class that iterates over the data array
return new Iterator() {
public Object remove(){
for(int j=i+1 ; j<=nextEmptySlot-1 ; j++) {
this.data[j-1] = this.data[j];
}
return (this.data.data[i]);
}
public int hasNext(){
if(this.data.data[i+1] != null) return 1;
else return 0;
}
public Object next(){
i++;
if (hasNext()==1){
return this.data.data[i];
}
else if (hasNext()==0){
throw UnsupportedOperationException();
}
return this;
}
};
}
}
You need to import java.util.Iterator;
This code isn't even wrong; check out the Iterator methods:
http://download.oracle.com/javase/1.4.2/docs/api/java/util/Iterator.html
Your Iterator does not implement the java.util.Iterator interface; using the same name doth not make it one.
Look at your method:
public int hasNext()
The java.util.Iterator hasNext() returns a boolean.
This is utterly wrong.
I have a class Polygon on which I wish to implement two iterators: one to run through all elements (vertices and edges in alternating order) just ONCE, and another to run through them ad infinitum (cyclically).
From a for-each usage standpoint, my guess is that I am only going to be able to have one of the above be the default iterator that can be used with for-each, via implementation of Iterable.iterator(). Is this correct? Or is there a way I could use for-each with both?
Just add two methods returning two different Iterators, one for each case:
public Iterable<String> eachOnce() {
List<String> allResults = new ArrayList<String>();
// fill list
return allResults;
}
public Iterable<String> eachCyclic() {
return new Iterable<String>() {
public Iterator<String> iterator() {
return new Iterator<String>() {
public boolean hasNext() {
return true;
}
public String next() {
// TODO implement
return null;
}
public void remove() {
// do nothing
}
};
}
};
}
This is just an example with a List of Strings, just adapt.
Instead of
for (Polygon p : polygons) { }
just use
for (Polygon p : polygons.eachOnce()) { }
or the cyclic edition
An answer I think is better than those already presented is a method that turns any Iterable into a cyclic one.
public class IterableUtils {
public static class CyclicIterator<T> implements Iterator<T> {
private final Iterable<T> inner;
private Iterator<T> currentIter;
public CyclicIterator(Iterable<T> inner) {
this.inner = inner;
}
public boolean hasNext() {
if (currentIter == null || !currentIter.hasNext()) {
currentIter = inner.iterator();
}
return currentIter.hasNext();
}
public T next() {
if (currentIter == null || !currentIter.hasNext()) {
currentIter = inner.iterator();
}
return currentIter.next();
}
public void remove() {
currentIter.remove();
}
}
public static <T> Iterable<T> cycle(final Iterable<T> i) {
return new Iterable<T>() {
public Iterator<T> iterator() { return new CyclicIterator<T>(i); }
};
}
}
Then you can just implement the single iterator method in the Polygon class and use
for (Element e: polygon) {
...
}
to iterate once and
for (Element e: cycle(polygon)) {
...
}
to iterate endlessly. As a bonus, the cycle modifier can be applied to any iterable.
Is it possible to merge iterators in Java? I have two iterators and I want to combine/merge them so that I could iterate though their elements in one go (in same loop) rather than two steps. Is that possible?
Note that the number of elements in the two lists can be different therefore one loop over both lists is not the solution.
Iterator<User> pUsers = userService.getPrimaryUsersInGroup(group.getId());
Iterator<User> sUsers = userService.getSecondaryUsersInGroup(group.getId());
while(pUsers.hasNext()) {
User user = pUsers.next();
.....
}
while(sUsers.hasNext()) {
User user = sUsers.next();
.....
}
Guava (formerly Google Collections) has Iterators.concat.
Also the Apache Commons Collection have several classes for manipulating Iterators, like the IteratorChain, that wraps a number of Iterators.
You could create your own implementation of the Iterator interface which iterates over the iterators:
public class IteratorOfIterators implements Iterator {
private final List<Iterator> iterators;
public IteratorOfIterators(List<Iterator> iterators) {
this.iterators = iterators;
}
public IteratorOfIterators(Iterator... iterators) {
this.iterators = Arrays.asList(iterators);
}
public boolean hasNext() { /* implementation */ }
public Object next() { /* implementation */ }
public void remove() { /* implementation */ }
}
(I've not added generics to the Iterator for brevity.) The implementation is not too hard, but isn't the most trivial, you need to keep track of which Iterator you are currently iterating over, and calling next() you'll need to iterate as far as you can through the iterators until you find a hasNext() that returns true, or you may hit the end of the last iterator.
I'm not aware of any implementation that already exists for this.
Update:
I've up-voted Andrew Duffy's answer - no need to re-invent the wheel. I really need to look into Guava in more depth.
I've added another constructor for a variable number of arguments - almost getting off topic, as how the class is constructed here isn't really of interest, just the concept of how it works.
I haven't written Java code in a while, and this got me curious to whether I've still "got it".
First try:
import java.util.Iterator;
import java.util.Arrays; /* For sample code */
public class IteratorIterator<T> implements Iterator<T> {
private final Iterator<T> is[];
private int current;
public IteratorIterator(Iterator<T>... iterators)
{
is = iterators;
current = 0;
}
public boolean hasNext() {
while ( current < is.length && !is[current].hasNext() )
current++;
return current < is.length;
}
public T next() {
while ( current < is.length && !is[current].hasNext() )
current++;
return is[current].next();
}
public void remove() { /* not implemented */ }
/* Sample use */
public static void main(String... args)
{
Iterator<Integer> a = Arrays.asList(1,2,3,4).iterator();
Iterator<Integer> b = Arrays.asList(10,11,12).iterator();
Iterator<Integer> c = Arrays.asList(99, 98, 97).iterator();
Iterator<Integer> ii = new IteratorIterator<Integer>(a,b,c);
while ( ii.hasNext() )
System.out.println(ii.next());
}
}
You could of course use more Collection classes rather than a pure array + index counter, but this actually feels a bit cleaner than the alternative. Or am I just biased from writing mostly C these days?
Anyway, there you go. The answer to you question is "yes, probably".
public class IteratorJoin<T> implements Iterator<T> {
private final Iterator<T> first, next;
public IteratorJoin(Iterator<T> first, Iterator<T> next) {
this.first = first;
this.next = next;
}
#Override
public boolean hasNext() {
return first.hasNext() || next.hasNext();
}
#Override
public T next() {
if (first.hasNext())
return first.next();
return next.next();
}
}
Starting with Java 8 and later this can be done without external dependencies using Stream API. This also allows concatenation of iterator with other types of streams.
Streams.concat(StreamSupport.stream(<iter1>, false), StreamSupport.stream(<iter2>, false));
move your loop to a method and pass the iterator to method.
void methodX(Iterator x) {
while (x.hasNext()) {
....
}
}
an iterator comes FROM a collection or a set.
why not use the method already available
Collection.addAll(Collection c);
and then create your iterator from the last object.
this way, your iterator will iterate all the contents of both collection.
You can use my version of an extendable iterator. It uses a double-ended queue of iterators which to me makes sense:
import java.util.Deque;
import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedDeque;
public class ExtendableIterator<T> implements Iterator<T> {
public Deque<Iterator<T>> its = new ConcurrentLinkedDeque<Iterator<T>>();
public ExtendableIterator() {
}
public ExtendableIterator(Iterator<T> it) {
this();
this.extend(it);
}
#Override
public boolean hasNext() {
// this is true since we never hold empty iterators
return !its.isEmpty() && its.peekLast().hasNext();
}
#Override
public T next() {
T next = its.peekFirst().next();
if (!its.peekFirst().hasNext()) {
its.removeFirst();
}
return next;
}
public void extend(Iterator<T> it) {
if (it.hasNext()) {
its.addLast(it);
}
}
}
The Merged Iterator:
import static java.util.Arrays.asList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
public class ConcatIterator<T> implements Iterator<T> {
private final List<Iterable<T>> iterables;
private Iterator<T> current;
#SafeVarargs
public ConcatIterator(final Iterable<T>... iterables) {
this.iterables = new LinkedList<>(asList(iterables));
}
#Override
public boolean hasNext() {
checkNext();
return current != null && current.hasNext();
}
#Override
public T next() {
checkNext();
if (current == null || !current.hasNext()) throw new NoSuchElementException();
return current.next();
}
#Override
public void remove() {
if (current == null) throw new IllegalStateException();
current.remove();
}
private void checkNext() {
while ((current == null || !current.hasNext()) && !iterables.isEmpty()) {
current = iterables.remove(0).iterator();
}
}
}
The concat method to create an Iterable:
#SafeVarargs
public static <T> Iterable<T> concat(final Iterable<T>... iterables) {
return () -> new ConcatIterator<>(iterables);
}
Simple JUnit test:
#Test
public void testConcat() throws Exception {
final Iterable<Integer> it1 = asList(1, 2, 3);
final Iterable<Integer> it2 = asList(4, 5);
int j = 1;
for (final int i : concat(it1, it2)) {
assertEquals(j, i);
j++;
}
}
I would refactor the original design from:
Iterator<User> pUsers = userService.getPrimaryUsersInGroup(group.getId());
Iterator<User> sUsers = userService.getSecondaryUsersInGroup(group.getId());
To something like:
Iterator<User> users = userService.getUsersInGroup(group.getId(), User.PRIMARY, User.SECONDARY, ...);
You can try ConcatIterator from Cactoos:
Iterator<String> names = new ConcatIterator<>(
Arrays.asList("Sarah", "Mary").iterator(),
Arrays.asList("Jeff", "Johnny").iterator(),
);
Also check ConcatIterable, which concatenates Iterables.
In the Apache Commons Collections there is public static <E> Iterator<E> org.apache.commons.collections4.IteratorUtils.chainedIterator(Collection<Iterator<? extends E>> iterators) that says
Gets an iterator that iterates through a collections of Iterators one after another.
which should be what you want.
import java.util.Arrays;
import java.util.Iterator;
import org.apache.commons.collections4.IteratorUtils;
//also works: import org.apache.commons.collections.IteratorUtils;
class Scratch {
public static void main( String[] args ) {
final Iterator<String> combinedIterator = IteratorUtils.chainedIterator(
Arrays.asList( "a", "b", "c" ).iterator(),
Arrays.asList( "1", "2", "3" ).iterator()
);
while( combinedIterator.hasNext() ){
System.out.println( combinedIterator.next() );
}
// "abc123" will have been printed out
}
}
every Iterator object holds own memory location (adress), so you can't simply "merge" them. except if you extend iterator class and write your own implementation there.
If you are dealing with the same number of objects in both iterators an alternative solution would be to process two iterators in one loop like this :
while (iterator1.hasNext() && iterator2.hasNext()) {
// code
}