'Shortest way to get an Iterator over a range of Integers in Java
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()
Solution 1:[1]
This implementation does not have a memory footprint.
/**
* @param begin inclusive
* @param end exclusive
* @return list of integers from begin to end
*/
public static List<Integer> range(final int begin, final int end) {
return new AbstractList<Integer>() {
@Override
public Integer get(int index) {
return begin + index;
}
@Override
public int size() {
return end - begin;
}
};
}
Edit:
In Java 8 and later you can simply say:
IntStream.range(begin, end).iterator() // returns PrimitiveIterator.OfInt
or if you need the boxed version:
IntStream.range(begin, end).boxed().iterator() // returns Iterator<Integer>
Solution 2:[2]
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();
}
}
Solution 3:[3]
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();
}
}
Solution 4:[4]
An example using the guava framework. Note that this will not materialize the set (although you have to read the ContiguousSet implementation to verify that).
import com.google.common.collect.ContiguousSet;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.DiscreteDomains;
class RangeIterator {
public Iterator<Integer> range(int start, int length) {
assert length > 0;
Range<Integer> dim_range = Ranges.closedOpen(start, start + length);
DiscreteDomain<Integer> ints = DiscreteDomains.integers();
ContiguousSet<Integer> dim = dim_range.asSet(ints);
return dim.iterator();
}
}
Solution 5:[5]
A sample using stream API in java 8:
int first = 0;
int count = 10;
Iterator<Integer> it = IntStream.range(first, first + count).iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
Without iterator, it could be:
int first = 0;
int count = 10;
IntStream.range(first, first + count).forEach(i -> System.out.println(i));
Solution 6:[6]
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Joachim Sauer |
| Solution 3 | Jon Skeet |
| Solution 4 | |
| Solution 5 | btpka3 |
| Solution 6 |
