tags:

views:

1204

answers:

5

What's the shortest way to get an Iterator over a range of Integers in Java? In other words, implement the following:

/** 
* Returns an Iterator over the integers from first to first+count.
*/
Iterator<Integer> iterator(Integer first, Integer count);

Something like

(first..first+count).iterator()
+4  A: 

Straight-forward implementation of your homework:

List<Integer> ints = new ArrayList<Integer>();
for (int i = 0; i < count; i++) {
    ints.add(first + i);
}
Bombe
That's the right one if you take "shortest" seriously, except that you're missing "return ints.iterator();" ;-)
Joachim Sauer
+8  A: 

Untested. Mapping that onto "min, count" is left as an exercise for the reader.

public class IntRangeIterator implements Iterator<Integer> {
  private int nextValue;
  private final int max;
  public IntRangeIterator(int min, int max) {
    if (min > max) {
      throw new IllegalArgumentException("min must be <= max");
    }
    this.nextValue = min;
    this.max = max;
  }

  public boolean hasNext() {
    return nextValue <= max;
  }

  public Integer next() {
    if (!hasNext()) {
      throw new NoSuchElementException();
    }
    return Integer.valueOf(nextValue++);
  }

  public void remove() {
    throw new UnsupportedOperationException();
  }
}
Joachim Sauer
+5  A: 

If you actually want the shortest amount of code, then Bombe's answer is fine. However, it sucks memory for no good reason. If you want to implement it yourself, it would be something like:

import java.util.*;

public class IntegerRange implements Iterator<Integer>
{
    private final int start;
    private final int count;

    private int position = -1;

    public IntegerRange(int start, int count)
    {
        this.start = start;
        this.count = count;
    }

    public boolean hasNext()
    {
        return position+1 < count;
    }

    public Integer next()
    {
        if (position+1 >= count)
        {
            throw new NoSuchElementException();
        }
        position++;
        return start + position;
    }

    public void remove()
    {
        throw new UnsupportedOperationException();
    }
}
Jon Skeet
A: 

Here's teh codez, this one even supports remove() for no good reason. Untested.

import java.util.*;
import java.lang.*;



public class IntegerIterator implements Iterator<Integer> {

    private final int last;
    private int next;
    private int lastReturned = Integer.MIN_VALUE;
    private final List<Integer> removed = new LinkedList<Integer>();

    public IntegerIterator(Integer first, Integer count) {
     this.last = first+count;
     this.next = first;
    }

    public boolean hasNext() {  
     return last > next;
    }

    public synchronized Integer next() {
     if(next > last) throw new NoSuchElementException();
     lastReturned = next++;

     while(removed.contains(next)){
      next++;
     }  
     return Integer.valueOf(lastReturned);
    }

    public void remove() {

     if(lastReturned == Integer.MIN_VALUE) throw new IllegalStateException();
     removed.add(lastReturned);  
    }
}
Sietse
This is wrong. If you call next() count + 1 times, it will print last instead of throwing NoSuchElementException . Moreover, since removed can only contain elements that are already returned, it has /no/ purpose.
Matthew Flaschen
+2  A: 

It's generally considered good style to pass around Collection and friends instead of Iterator (see this FAQ entry), so I'd recommend something like

public final class IntegerRange implements Set<Integer> {
        final LinkedHashSet<Integer> backingList;
        public IntegerRange(final int start, final int count) {
                backingList = new LinkedHashSet(count, 1.0f);
                for (int i=0; i < count; i++) {
                        backingList.set(i, start + i);
                }       
        }       
        /** Insert a bunch of delegation methods here */
}

and then just use .iterator() when you need to pass an Iterator to whatever framework you're using.

UPDATE: Obviously, this code isn't lazy. If you can't afford the extra memory overhead of storing (potentially) 2^32-1 Integers, you should use a different solution. Also, nothing about the type guarantees the range will be sorted (even though it is, based on the implementation). If you need to guarantee sorting, you could look into implementing SortedSet and backing it with a TreeSet, but it will take longer to build the range. Honestly, if you are that concerned with getting the details right, it might be worth your effort to look for a library. Tapestry has an internal version, for instance.

Hank Gay
Why implement that in a backing set? It's rather easy to implement that without storing all Integers (which can be rather memory intensive), as long as you don't need to support add() and remove(). I'd also add that a List would be more fitting (as there's definitely some order)
Joachim Sauer
RE: List -> cretzel didn't specify a ListIterator, and Iterator makes no ordering guarantees, so I went with the closest mapping (Collection), though in retrospect, I would have used Set.RE: lazy -> that seemed like a lot more work, plus cretzel made no mention of not needing remove() support.
Hank Gay
The FAQ entry you are referring to tells us that we should not pass Iterators around a collection of objects. But if you are interested not in the collection but in the iteration process, passing an Iterator is quite OK.
Guillaume
I think Collection vs. Iterator really depends. The guys at Google seem to favor Iterator for their applications: see "Why so much emphasis on Iterators and Iterables?" here: http://code.google.com/p/google-collections/wiki/Faq
Dave Ray