Кратчайший способ получить итератор для целого ряда в Java - PullRequest
21 голосов
/ 16 декабря 2008

Какой самый короткий способ получить итератор для целого ряда целых чисел в Java? Другими словами, реализовать следующее:

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

Что-то вроде

(first..first+count).iterator()

Ответы [ 7 ]

67 голосов
/ 26 июля 2011

Эта реализация не имеет места в памяти.

/**
 * @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:

В Java 8 вы можете просто сказать:

IntStream.range(begin, end).iterator()                // returns PrimitiveIterator.OfInt

или, если вам нужна коробочная версия:

IntStream.range(begin, end).boxed().iterator()        // returns Iterator<Integer>
15 голосов
/ 16 декабря 2008

непроверенная. Отображение этого на «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();
  }
}
9 голосов
/ 16 декабря 2008

Если вы действительно хотите самый короткий объем кода, то 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();
    }
}
7 голосов
/ 31 октября 2011

Пример использования фреймворка 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();
    }
}
4 голосов
/ 20 апреля 2016

Пример с использованием потокового API в 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());
}

Без итератора это может быть:

int first = 0;
int count = 10;
IntStream.range(first, first + count).forEach(i -> System.out.println(i));
4 голосов
/ 16 декабря 2008

Простое выполнение вашей домашней работы:

List<Integer> ints = new ArrayList<Integer>();
for (int i = 0; i < count; i++) {
    ints.add(first + i);
}
2 голосов
/ 16 декабря 2008

Обычно считается хорошим стилем передавать Collection и друзей вместо Iterator (см. этот раздел часто задаваемых вопросов ), поэтому я рекомендую что-то вроде

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 , но для построения диапазона потребуется больше времени. Честно говоря, если вы заинтересованы в том, чтобы получить правильные детали, возможно, вам стоит поискать библиотеку. Гобелен имеет внутреннюю версию , например.

...