Как создать список или массив последовательных целых чисел в Java?

Есть ли короткий и приятный способ сгенерировать Listили, возможно, Integer[]или int[]с последовательными значениями от некоторого значения startдо endзначение?

То есть что-то короче, но эквивалентно 1 следующему:

void List makeSequence(int begin, int end) {
  List ret = new ArrayList<>(end - begin + 1);
  for (int i=begin; i<=end; i++) {
    ret.add(i);
  }
  return ret;  
}

Использование гуавы прекрасно.

Обновление:

Анализ производительности

Поскольку на этот вопрос было получено несколько хороших ответов, как с использованием собственных библиотек Java 8, так и сторонних библиотек, я решил проверить производительность всех решений.

Первый тест просто проверяет создание списка из 10 элементов [1..10]с использованием следующих методов:

  • classicArrayList:код, приведенный выше в моем вопросе (и по существу такой же, как ответ adarshr ).
  • eclipseCollections:код, приведенный в ответе Дональда ниже с использованием Eclipse Collections 8.0.
  • guavaRange:код, указанный в ответе daveb ниже. Технически это создает не List, а скорее ContiguousSet-, но поскольку он реализует Iterableв порядке -, он в основном работает для моих целей.
  • intStreamRange:код, приведенный в ответе Владимира ниже, в котором используется IntStream.rangeClosed()-, представленный в Java 8.
  • streamIterate:код, указанный в ответе Каталина ниже, который также использует IntStreamфункциональные возможности, представленные в Java 8.

Вот результаты в кило -операций в секунду (более высокие числа лучше ), для всего вышеперечисленного со списками размером 10:

List creation throughput

... и снова для списков размером 10 000:

enter image description here

Последняя диаграмма верна -решения, отличные от Eclipse и Guava, слишком медленны, чтобы получить даже полоску с одним пикселем!Быстрые решения в 10 000–20 000 раз быстрее, чем остальные.

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

Давайте сделаем что-нибудь более реалистичное, а также переберем все целые числа, просуммировав их. Так что в случае с вариантом IntStream.rangeClosedбенчмарк выглядит как:

@Benchmark
public int intStreamRange() {
    List ret = IntStream.rangeClosed(begin, end).boxed().collect(Collectors.toList());  

    int total = 0;
    for (int i : ret) {
        total += i;
    }
    return total;  
}

Здесь картинки сильно меняются, хотя решения без материализации -по-прежнему самые быстрые. Здесь длина = 10:

List<Integer> Iteration (length=10)

... и длина = 10 000:

List<Integer> Iteration (length=10,000)

Долгая итерация по многим элементам во многом выравнивает ситуацию, но eclipse и guava остаются более чем в два раза быстрее даже в тесте на 10 000 элементов.

Итак, если вы действительно хотите List, коллекции eclipse кажутся лучшим выбором -, но, конечно, если вы используете потоки более естественным образом (, например, забывая .boxed()и, выполняя сокращение примитивного домена ), вы, вероятно, окажетесь быстрее, чем все эти варианты.


1 Возможно, за исключением обработки ошибок, например, если endbegin, или если размер превышает некоторые ограничения реализации или JVM (, например, массивы больше, чем 2^31-1.

105
задан Dukeling 8 February 2018 в 21:04
поделиться