resueltos - matriz java filas columnas
¿Cómo puedo generar una lista o matriz de enteros secuenciales en Java? (8)
¿Existe una manera breve y dulce de generar una List<Integer>
, o tal vez un Integer[]
o int[]
, con valores secuenciales desde algún valor de start
hasta un valor end
?
Es decir, algo más corto que, pero equivalente a 1 de los siguientes:
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 guayaba está bien.
Actualizar:
Análisis de rendimiento
Dado que esta pregunta ha recibido varias buenas respuestas, tanto con el uso de Java 8 nativa y bibliotecas de terceros, pensé que 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 arriba en mi pregunta (y esencialmente lo mismo que la respuesta de adarshr).
- eclipseCollections : el código proporcionado a continuación en la respuesta de Donald 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 unContiguousSet<Integer>
- pero dado que implementaIterable<Integer>
en orden, en general funciona para mis propósitos. - intStreamRange : el código proporcionado en la respuesta de Vladimir a continuación, que usa
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 funcionalidad
IntStream
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 obtener una sola barra de píxeles! Las soluciones rápidas son entre 10.000 y 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 de los puntos de inicio y final. Cada elemento se crea según sea necesario durante la iteración. Dado que en realidad no iteramos en esta prueba, el costo se difiere. Todas las otras soluciones realmente 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 variante IntStream.rangeClosed
, la 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 sin materialización siguen siendo las más rápidas. Aquí está la longitud = 10:
... y longitud = 10,000:
La larga iteración sobre muchos elementos empareja mucho las cosas, pero el eclipse y la guayaba son más del doble de rápido incluso en la prueba de los 10.000 elementos.
Entonces, si realmente quieres un List<Integer>
, las colecciones de eclipse parecen ser la mejor opción, pero por supuesto si usas streams de una forma más nativa (por ejemplo, olvidando .boxed()
y haciendo una reducción en el dominio primitivo) you '' Probablemente termine más rápido que todas estas 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 (p. Ej., Arreglos mayores a 2^31-1
.
Bueno, este trazador de líneas puede calificar (usa rangos de guayaba )
ContiguousSet<Integer> integerList = ContiguousSet.create(Range.closedOpen(0, 10), DiscreteDomain.integers());
System.out.println(integerList);
Esto no crea una List<Integer>
, pero ContiguousSet
ofrece la misma funcionalidad, en particular la implementación de Integer<Integer>
que permite la implementación de foreach
de la misma manera que List<Integer>
.
En versiones anteriores (en algún lugar antes de Guava 14) puede usar esto:
ImmutableList<Integer> integerList = Ranges.closedOpen(0, 10).asSet(DiscreteDomains.integers()).asList();
System.out.println(integerList);
Ambos producen:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Con Java 8 es tan simple que ya no necesita ningún método aparte:
List<Integer> range = IntStream.rangeClosed(start, end)
.boxed().collect(Collectors.toList());
Este podría funcionar para usted ....
void List<Integer> makeSequence(int begin, int end) {
AtomicInteger ai=new AtomicInteger(begin);
List<Integer> ret = new ArrayList(end-begin+1);
while ( end-->begin) {
ret.add(ai.getAndIncrement());
}
return ret;
}
Esto es lo más corto que pude encontrar.
Versión de lista
public List<Integer> makeSequence(int begin, int end)
{
List<Integer> ret = new ArrayList<Integer>(++end - begin);
for (; begin < end; )
ret.add(begin++);
return ret;
}
Array Version
public int[] makeSequence(int begin, int end)
{
if(end < begin)
return null;
int[] ret = new int[++end - begin];
for (int i=0; begin < end; )
ret[i++] = begin++;
return ret;
}
Esto es lo más corto que puedo obtener usando Core Java.
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;
}
La siguiente versión Java de una línea generará [1, 2, 3 ... 10]. El primer arg de iterate
es el primer nr en la secuencia, y el primer arg de limit
es el último número.
List<Integer> numbers = Stream.iterate(1, n -> n + 1)
.limit(10)
.collect(Collectors.toList());
Podría usar rangos de guayaba
Puedes obtener un SortedSet
usando
ImmutableSortedSet<Integer> set = Ranges.open(1, 5).asSet(DiscreteDomains.integers());
// set contains [2, 3, 4]
Puede usar la clase Interval
de Eclipse Collections .
List<Integer> range = Interval.oneTo(10);
range.forEach(System.out::print); // prints 12345678910
La clase Interval
es floja, por lo que no almacena todos los valores.
LazyIterable<Integer> range = Interval.oneTo(10);
System.out.println(range.makeString(",")); // prints 1,2,3,4,5,6,7,8,9,10
Su método podría implementarse de la siguiente manera:
public List<Integer> makeSequence(int begin, int end) {
return Interval.fromTo(begin, end);
}
Si desea evitar el boxeo como enteros, pero le gustaría una estructura de lista como resultado, puede usar IntList
con IntInterval
desde Eclipse Collections.
public IntList makeSequence(int begin, int end) {
return IntInterval.fromTo(begin, end);
}
IntList
tiene los métodos sum()
, min()
, minIfEmpty()
, max()
, maxIfEmpty()
, average()
y median()
disponibles en la interfaz.
Actualización para mayor claridad: 27/11/2017
Un Interval
es una List<Integer>
, pero es flojo e inmutable. Es extremadamente útil para generar datos de prueba, especialmente si manejas mucho con colecciones. Si lo desea, puede copiar fácilmente un intervalo en una List
, Set
o Bag
siguiente manera:
Interval integers = Interval.oneTo(10);
Set<Integer> set = integers.toSet();
List<Integer> list = integers.toList();
Bag<Integer> bag = integers.toBag();
Un IntInterval
es una IntList
que extiende IntList
. También tiene métodos de conversión.
IntInterval ints = IntInterval.oneTo(10);
IntSet set = ints.toSet();
IntList list = ints.toList();
IntBag bag = ints.toBag();
Un Interval
y un IntInterval
no tienen el mismo contrato equals
.
Actualización para Eclipse Collections 9.0
Ahora puede crear colecciones primitivas a partir de flujos primitivos. Existen con ofAll
métodos y de ofAll
dependiendo de su preferencia. Si tienes curiosidad, te explico por qué tenemos ambas here . Estos métodos existen para listas Int / Long / Double mutables e inmutables, Sets, Bags y Stacks.
Assert.assertEquals(
IntInterval.oneTo(10),
IntLists.mutable.withAll(IntStream.rangeClosed(1, 10)));
Assert.assertEquals(
IntInterval.oneTo(10),
IntLists.immutable.withAll(IntStream.rangeClosed(1, 10)));
Nota: soy un committer para las colecciones de Eclipse