¿Hay una manera corta y dulce de generar un List<Integer>
, o tal vez un Integer[]
o int[]
, con valores secuenciales de algún start
valor a un end
valor?
Es decir, algo más corto que, pero equivalente a 1, lo siguiente:
void List<Integer> makeSequence(int begin, int end) {
List<Integer> ret = new ArrayList<>(end - begin + 1);
for (int i=begin; i<=end; i++) {
ret.add(i);
}
return ret;
}
El uso de la guayaba está bien.
Actualizar:
Análisis de rendimiento
Dado que esta pregunta ha recibido varias buenas respuestas, utilizando tanto Java 8 nativas como bibliotecas de terceros, pensé en probar el rendimiento de todas las soluciones.
La primera prueba simplemente prueba la creación de una lista de 10 elementos [1..10]
utilizando los siguientes métodos:
- classicArrayList : el código dado anteriormente en mi pregunta (y esencialmente el mismo que la respuesta de adarshr).
- eclipseCollections : el código dado en la respuesta de Donald a continuación usando Eclipse Collections 8.0.
- guavaRange : el código dado en la respuesta de daveb a continuación. Técnicamente, esto no crea un
List<Integer>
sino más bien unContiguousSet<Integer>
, pero como se implementaIterable<Integer>
en orden, funciona principalmente para mis propósitos. - intStreamRange : el código proporcionado en la respuesta de Vladimir a continuación, que utiliza
IntStream.rangeClosed()
, que se introdujo en Java 8. - streamIterate : el código proporcionado en la respuesta de Catalin a continuación, que también utiliza la
IntStream
funcionalidad introducida en Java 8.
Aquí están los resultados en kilo-operaciones por segundo (los números más altos son mejores), para todo lo anterior con listas de tamaño 10:
... y nuevamente para listas de tamaño 10,000:
Ese último gráfico es correcto: las soluciones que no sean Eclipse y Guava son demasiado lentas para incluso obtener una sola barra de píxeles. Las soluciones rápidas son 10,000 a 20,000 veces más rápidas que el resto.
Lo que está sucediendo aquí, por supuesto, es que las soluciones de guayaba y eclipse en realidad no materializan ningún tipo de lista de 10,000 elementos, simplemente son envoltorios de tamaño fijo alrededor del inicio y los puntos finales. Cada elemento se crea según sea necesario durante la iteración. Como no realizamos iteraciones en esta prueba, el costo se difiere. Todas las otras soluciones en realidad materializan la lista completa en la memoria y pagan un alto precio en un punto de referencia de solo creación.
Hagamos algo un poco más realista y también iteremos sobre todos los enteros, resumiéndolos. Entonces, en el caso de la IntStream.rangeClosed
variante, el punto de referencia se ve así:
@Benchmark
public int intStreamRange() {
List<Integer> ret = IntStream.rangeClosed(begin, end).boxed().collect(Collectors.toList());
int total = 0;
for (int i : ret) {
total += i;
}
return total;
}
Aquí, las imágenes cambian mucho, aunque las soluciones que no se materializan siguen siendo las más rápidas. Aquí está la longitud = 10:
... y longitud = 10,000:
La larga iteración sobre muchos elementos iguala las cosas mucho, pero el eclipse y la guayaba permanecen más del doble de rápido incluso en la prueba de 10,000 elementos.
Entonces, si realmente desea una List<Integer>
, las colecciones de eclipse parecen ser la mejor opción, pero, por supuesto, si usa secuencias de una manera más nativa (por ejemplo, olvidando .boxed()
y haciendo una reducción en el dominio primitivo), probablemente terminará más rápido que todos estos variantes
1 Quizás con la excepción del manejo de errores, por ejemplo, si end
< begin
, o si el tamaño excede algunos límites de implementación o JVM (por ejemplo, matrices más grandes que 2^31-1
.