Есть ли что-то вроде Enumerable.Range(x,y) в Java?

Есть ли что-то вроде C#/.NET

IEnumerable<int> range = Enumerable.Range(0, 100); //.NET

на Яве?


person Simon    schedule 01.06.2010    source источник


Ответы (3)


Отредактировано: как Java 8, это возможно с java.util.stream.IntStream.range(int startInclusive, int endExclusive)

До Java8:

В Java такого нет, но у вас может быть что-то вроде этого:

import java.util.Iterator;

public class Range implements Iterable<Integer> {
    private int min;
    private int count;

    public Range(int min, int count) {
        this.min = min;
        this.count = count;
    }

    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            private int cur = min;
            private int count = Range.this.count;
            public boolean hasNext() {
                return count != 0;
            }

            public Integer next() {
                count--;
                return cur++; // first return the cur, then increase it.
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}

Например, вы можете использовать Range следующим образом:

public class TestRange {

    public static void main(String[] args) {
        for (int i : new Range(1, 10)) {
            System.out.println(i);
        }
    }

}

Также, если вам не нравится использовать new Range(1, 10) напрямую, вы можете использовать для него фабричный класс:

public final class RangeFactory {
    public static Iterable<Integer> range(int a, int b) {
        return new Range(a, b);
    }
}

А вот и наш заводской тест:

public class TestRangeFactory {

    public static void main(String[] args) {
        for (int i : RangeFactory.range(1, 10)) {
            System.out.println(i);
        }
    }

}

Я надеюсь, что они будут полезны :)

person Ebrahim Byagowi    schedule 09.03.2012
comment
Хорошо сделано. Найдите старый вопрос и дайте превосходный ответ. :) - person Kirk Woll; 09.03.2012
comment
Небольшое дополнение, контракт для next() заключается в том, чтобы выдать NoSuchElementException в случае, если метод вызывается, когда в итераторе больше нет элементов, поэтому я предлагаю добавить if (!hasNext()) throw new NoSuchElementException() в качестве первого действия для next(). :) - person Ibrahim Arief; 09.09.2014

В Java нет встроенной поддержки для этого, однако ее очень легко создать самостоятельно. По большому счету API-интерфейсы Java предоставляют все, что вам нужно для такого рода функций, но не объединяют их в готовом виде.

Java использует подход, согласно которому существует бесконечное количество способов комбинировать вещи, так зачем отдавать предпочтение нескольким комбинациям над другими. При правильном наборе строительных блоков все остальное можно легко построить (это тоже философия Unix).

Другие языковые API (например, C# и Python) имеют более взвешенный взгляд, они выбирают несколько вещей, чтобы сделать их действительно простыми, но все же допускают более эзотерические комбинации.

Типичный пример проблемы с подходом Java можно увидеть в Java IO библиотека. Канонический способ создания текстового файла для вывода:

BufferedWriter out = new BufferedWriter(new FileWriter("out.txt"));

Библиотека Java IO использует шаблон декоратора, который действительно хорошая идея для гибкости, но наверняка чаще всего вам нужен буферизованный файл? Сравните это с эквивалентом в Python, который делает типичный вариант использования действительно простым:

out = file("out.txt","w")
person Tendayi Mawushe    schedule 01.06.2010
comment
Да, ты прав. Просто хотел узнать, есть ли что-то встроенное. - person Simon; 01.06.2010

Вы можете создать подкласс Arraylist для достижения того же:

public class Enumerable extends ArrayList<Integer> {   
   public Enumerable(int min, int max) {
     for (int i=min; i<=max; i++) {
       add(i);
     }
   }    
}

Затем используйте итератор, чтобы получить последовательность целых чисел от минимального до максимального (включая оба)

ИЗМЕНИТЬ

Как уже упоминал sepp2k, приведенное выше решение быстрое, грязное и практичное, но имеет некоторые серьезные недостатки (не только O (n) в пространстве, хотя оно должно иметь O (1)). Для более серьезной эмуляции класса C# я бы предпочел написать собственный класс Enumerable, который реализует Iterable и собственный итератор (но не здесь и сейчас;)).

person Andreas Dolk    schedule 01.06.2010
comment
Спасибо, Андреас. Значит нет? - person Simon; 01.06.2010
comment
Не в базовом API Java, на самом деле, но, возможно, что-то есть в одной из многочисленных библиотек Apache Commons. Туда я бы посмотрел в первую очередь. - person Andreas Dolk; 01.06.2010
comment
Хорошо ... добавьте свой комментарий к своему ответу, чтобы я мог проголосовать за него и пометить как ответ. :) - person Simon; 01.06.2010
comment
Обратите внимание, что это решение на самом деле будет занимать место, пропорциональное длине диапазона (в отличие от Enumerable.Range, в котором хранятся только начальное и конечное значения), что может быть неприемлемо для больших диапазонов. - person sepp2k; 01.06.2010
comment
Отзывов гораздо больше (и я бы не стал использовать этот код в собственных проектах), но ОП не сказал, почему он хочет использовать/эмулировать тип Enumerable из С#. Лучшие требования, лучшие решения. - person Andreas Dolk; 01.06.2010
comment
@ sepp2k: Нет, использование памяти только откладывается. Как только вы вызываете GetEnumerator или используете его в foreach, IEnumerable заполняется фактическими значениями. Документы MSDN: msdn.microsoft.com/en-us /библиотека/ - person Powerlord; 01.06.2010
comment
@R.Bemrose: я только что запустил foreach(int i in Enumerable.Range(0, 1000000000)) {/*...*/} без видимого увеличения потребления памяти, поэтому я убежден, что он не хранит в памяти все значения от 0 до 1000000000. - person sepp2k; 01.06.2010