Javaで整数の範囲でイテレータを取得する最短の方法は何ですか?つまり、次のように実装します。
/**
* Returns an Iterator over the integers from first to first+count.
*/
Iterator<Integer> iterator(Integer first, Integer count);
何かのようなもの
(first..first+count).iterator()
宿題の簡単な実装:
List<Integer> ints = new ArrayList<Integer>();
for (int i = 0; i < count; i++) {
ints.add(first + i);
}
この実装にはメモリフットプリントがありません。
/**
* @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;
}
};
}
Java 8では、次のように簡単に言うことができます。
IntStream.range(begin, end).iterator() // returns PrimitiveIterator.OfInt
または、ボックス版が必要な場合:
IntStream.range(begin, end).boxed().iterator() // returns Iterator<Integer>
テストされていません。それを「min、count」にマッピングすることは、読者の練習問題として残されています。
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();
}
}
実際に最短量のコードが必要な場合は、Bombeの答えで問題ありません。しかし、それは正当な理由もなくメモリを吸います。自分で実装したい場合は、次のようになります。
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();
}
}
Guavaフレームワークを使用した例。これはセットを具体化しないことに注意してください(ただし、それを確認するにはContiguousSet実装を読む必要があります)。
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();
}
}
Java 8:でストリームAPIを使用したサンプル
int first = 0;
int count = 10;
Iterator<Integer> it = IntStream.range(first, first + count).iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
イテレータがない場合は、次のようになります。
int first = 0;
int count = 10;
IntStream.range(first, first + count).forEach(i -> System.out.println(i));
一般に、Collection
の代わりにIterator
とその友達を渡すのが良いスタイルだと考えられています( this FAQ entry を参照)。 dのようなものをお勧めします
_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 */
}
_
次に、使用しているフレームワークにIterator
を渡す必要がある場合は、.iterator()
を使用します。
更新:明らかに、このコードは怠惰ではありません。 2 ^ 32-1 Integer
sを(潜在的に)格納するための追加のメモリオーバーヘッドを許容できない場合は、別のソリューションを使用する必要があります。また、タイプについては、範囲がソートされることを保証するものは何もありません(実装に基づいていますが)。並べ替えを保証する必要がある場合は、 SortedSet を実装し、 TreeSet でバックアップすることを検討できますが、範囲の構築には時間がかかります。正直なところ、詳細を正しく理解することに関心がある場合は、ライブラリを探す価値があるかもしれません。たとえば、タペストリーには 内部バージョン があります。