¿Cómo convertir una ArrayList que contiene enteros a una matriz int primitiva?

297

Estoy tratando de convertir una ArrayList que contiene objetos Integer en primitivo int [] con el siguiente fragmento de código, pero arroja un error de tiempo de compilación. ¿Es posible convertir en Java?

List<Integer> x =  new ArrayList<Integer>();
int[] n = (int[])x.toArray(int[x.size()]);
Snehal
fuente
10
No es un duplicado EXACTO de esa pregunta (aunque tampoco muy lejos)
Jonik 05 de
1
Sí, esta es una ArrayList, "duplicar" se trata de una matriz normal.
Scott McIntyre
3
Si no necesita entradas primitivas, puede usar: List<Integer> x = new ArrayList<Integer>(); Integer[] n = x.toArray(new Integer[0]);
Evorlor

Respuestas:

219

Puede convertir, pero no creo que haya nada incorporado para hacerlo automáticamente:

public static int[] convertIntegers(List<Integer> integers)
{
    int[] ret = new int[integers.size()];
    for (int i=0; i < ret.length; i++)
    {
        ret[i] = integers.get(i).intValue();
    }
    return ret;
}

(Tenga en cuenta que esto arrojará una NullPointerException si alguno integerso cualquier elemento dentro de él es null).

EDITAR: según los comentarios, es posible que desee utilizar el iterador de lista para evitar costos desagradables con listas como LinkedList:

public static int[] convertIntegers(List<Integer> integers)
{
    int[] ret = new int[integers.size()];
    Iterator<Integer> iterator = integers.iterator();
    for (int i = 0; i < ret.length; i++)
    {
        ret[i] = iterator.next().intValue();
    }
    return ret;
}
Jon Skeet
fuente
21
Podría ser mejor iterar usando el iterador de la Lista (con para cada uno) para evitar golpes de rendimiento en las listas cuyo acceso no es O (1).
Matthew Willis
@Matthew: Sí, posiblemente, editará para dar eso como una alternativa.
Jon Skeet
1
También puede utilizar el hecho de que ArrayList implementa Iterable (mediante herencia de colección) y hacer: for (int n: integer) {ret [counter ++] = n; } ... e inicializa int counter = 0;
gardarh
8
mucho más fácil ahora en Java8:integers.stream().mapToInt(Integer::valueOf).toArray
Manish Patel
241

Si estas usando También hay otra forma de hacer esto.

int[] arr = list.stream().mapToInt(i -> i).toArray();

Lo que hace es:

  • obteniendo un Stream<Integer>de la lista
  • obtener un IntStreammapeo de cada elemento a sí mismo (función de identidad), desempaquetar el intvalor retenido por cada Integerobjeto (hecho automáticamente desde Java 5)
  • obtener la matriz de intllamandotoArray

También puede llamar explícitamente a intValuetravés de una referencia de método, es decir:

int[] arr = list.stream().mapToInt(Integer::intValue).toArray();

También vale la pena mencionar que podría obtener un NullPointerExceptionsi tiene alguna nullreferencia en la lista. Esto podría evitarse fácilmente agregando una condición de filtrado a la tubería de flujo de esta manera:

                       //.filter(Objects::nonNull) also works
int[] arr = list.stream().filter(i -> i != null).mapToInt(i -> i).toArray();

Ejemplo:

List<Integer> list = Arrays.asList(1, 2, 3, 4);
int[] arr = list.stream().mapToInt(i -> i).toArray(); //[1, 2, 3, 4]

list.set(1, null); //[1, null, 3, 4]
arr = list.stream().filter(i -> i != null).mapToInt(i -> i).toArray(); //[1, 3, 4]
Alexis C.
fuente
Veo que esto se puede usar para doubletipos; ¿No hay equivalente para los floattipos?
code_dredd
Vio el beneficio de Java 8 al elaborar una explicación.
Eugene
Y es por eso que la API Java 8+ Stream es hermosa.
Pranav A.
67

Google guayaba

Google Guava proporciona una forma ordenada de hacer esto llamando Ints.toArray.

List<Integer> list = ...;
int[] values = Ints.toArray(list);
Snehal
fuente
66
Creo que esta será la respuesta para mí: tomaré una biblioteca sobre una función de copiar y pegar cualquier día ... especialmente una biblioteca que probablemente ya utiliza un proyecto de tamaño decente. Espero que esta respuesta obtenga más votos positivos y visibilidad en el futuro.
Sean Connolly
61

Apache Commons tiene una clase ArrayUtils, que tiene un método toPrimitive () que hace exactamente esto.

import org.apache.commons.lang.ArrayUtils;
...
    List<Integer> list = new ArrayList<Integer>();
    list.add(new Integer(1));
    list.add(new Integer(2));
    int[] intArray = ArrayUtils.toPrimitive(list.toArray(new Integer[0]));

Sin embargo, como demostró Jon, es bastante fácil hacerlo usted mismo en lugar de usar bibliotecas externas.

Björn
fuente
2
Tenga en cuenta que este enfoque hará dos copias completas de la secuencia: una Integer [] creada por toArray y una int [] creada dentro de toPrimitive. La otra respuesta de Jon solo crea y llena una matriz. Algo a tener en cuenta si tiene listas grandes y el rendimiento es importante.
paraquat
Medí el rendimiento usando ArrayUtils vs puro java y en listas pequeñas (<25 elementos) puro java es más de 100 veces más rápido. Para los elementos de 3k, java puro sigue siendo casi 2 veces más rápido ... (ArrayList <Integer> -> int [])
Oskar Lund
@paraquat y Oskar Lund que en realidad no es correcto. Sí, el código proporcionado creará dos matrices, pero este enfoque no. El problema en este código aquí es el uso de una matriz de longitud cero como argumento. El código fuente ArrayList.toArray muestra que si los contenidos se ajustan, se utilizará la matriz original. Creo que, en una comparación justa, encontrará que este método es tan eficiente (si no más) y, por supuesto, menos código para mantener.
Sean Connolly
1
¿Cuál es el propósito del nuevo número entero [0]?
Adam Hughes
41

Creo que iterar usando el iterador de la Lista es una mejor idea, ya que list.get(i)puede tener un bajo rendimiento dependiendo de la implementación de la Lista:

private int[] buildIntArray(List<Integer> integers) {
    int[] ints = new int[integers.size()];
    int i = 0;
    for (Integer n : integers) {
        ints[i++] = n;
    }
    return ints;
}
Matthew Willis
fuente
6

usar Dollar debería ser bastante simple:

List<Integer> list = $(5).toList(); // the list 0, 1, 2, 3, 4  
int[] array = $($(list).toArray()).toIntArray();

Estoy planeando mejorar el DSL para eliminar la toArray()llamada intermedia

dfa
fuente
1
Oye, solo quería decir que no había visto a Dollar antes, pero definitivamente estoy probando mi próximo proyecto. Esa es una pequeña API ingeniosa que tienes allí, sigue con el buen trabajo :)
Bart Vandendriessche
4

Esto funciona bien para mí :)

Encontrado en https://www.techiedelight.com/convert-list-integer-array-int/

import java.util.Arrays;
import java.util.List;

class ListUtil
{
    // Program to convert list of integer to array of int in Java
    public static void main(String args[])
    {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

        int[] primitive = list.stream()
                            .mapToInt(Integer::intValue)
                            .toArray();

        System.out.println(Arrays.toString(primitive));
    }
}
angelhernandez
fuente
3

Me desconcierta que fomentemos métodos personalizados únicos cuando una biblioteca perfectamente buena y bien utilizada como Apache Commons ya haya resuelto el problema. Aunque la solución es trivial si no es absurda, es irresponsable fomentar ese comportamiento debido al mantenimiento y la accesibilidad a largo plazo.

Solo ve con Apache Commons

Andrew F.
fuente
77
Estoy de acuerdo con el comentario anterior. No solo arrastra en Apache Commons, sino que se traduce fácilmente en un gran conjunto de dependencias transitivas que también deben arrastrarse. Recientemente, pude eliminar una increíble cantidad de dependencias reemplazando una línea de código :-( Las dependencias son costosas y escribir código básico como este es una buena práctica
Peter Kriens
1
De acuerdo con @PeterKriens. En todo caso, la falla está en Java por no admitir conversiones simples como esta en sus tipos de datos estándar
Adam Hughes
3

Si está utilizando Eclipse Collections , puede utilizar el collectInt()método para cambiar de un contenedor de objetos a un contenedor int primitivo.

List<Integer> integers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
MutableIntList intList =
  ListAdapter.adapt(integers).collectInt(i -> i);
Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, intList.toArray());

Si puede convertir su ArrayLista FastList, puede deshacerse del adaptador.

Assert.assertArrayEquals(
  new int[]{1, 2, 3, 4, 5},
  Lists.mutable.with(1, 2, 3, 4, 5)
    .collectInt(i -> i).toArray());

Nota: Soy un committer para las colecciones de Eclipse.

Craig P. Motlin
fuente
3

Java 8:

int[] intArr = Arrays.stream(integerList).mapToInt(i->i).toArray();
EssaidiM
fuente
2

Arrays.setAll ()

    List<Integer> x = new ArrayList<>(Arrays.asList(7, 9, 13));
    int[] n = new int[x.size()];
    Arrays.setAll(n, x::get);

    System.out.println("Array of primitive ints: " + Arrays.toString(n));

Salida:

Matriz de entradas primitivas: [7, 9, 13]

Lo mismo funciona para una gran variedad de longo double, pero no para las matrices de boolean, char, byte, shorto float. Si tienes una lista realmente enorme, incluso hay un parallelSetAllmétodo que puedes usar en su lugar.

Para mí, esto es lo suficientemente bueno y elegante como para que no quiera obtener una biblioteca externa ni usar secuencias para ella.

Enlace de documentación: Arrays.setAll(int[], IntUnaryOperator)

Ole VV
fuente
1

Simplemente puede copiarlo a una matriz:

int[] arr = new int[list.size()];
for(int i = 0; i < list.size(); i++) {
    arr[i] = list.get(i);
}

No muy elegante; pero, oye, funciona ...

sagiksp
fuente
1

Una solución muy simple de una línea es:

Integer[] i = arrlist.stream().toArray(Integer[]::new);
PramodG
fuente
0

Este segmento de código funciona para mí, prueba esto:

Integer[] arr = x.toArray(new Integer[x.size()]);

Vale la pena mencionar que ArrayList debería declararse así:

ArrayList<Integer> list = new ArrayList<>();
usuario3444748
fuente
55
Hola, solo un suave recordatorio de que OP quiere una matriz primitiva, no una matriz de objetos.
OLIVER.KOO
3
Primitivo int no envoltorio Entero!
Bartzilla
-4
   List<Integer> list = new ArrayList<Integer>();

    list.add(1);
    list.add(2);

    int[] result = null;
    StringBuffer strBuffer = new StringBuffer();
    for (Object o : list) {
        strBuffer.append(o);
        result = new int[] { Integer.parseInt(strBuffer.toString()) };
        for (Integer i : result) {
            System.out.println(i);
        }
        strBuffer.delete(0, strBuffer.length());
    }
CodeMadness
fuente
1
Esta respuesta no funciona, devuelve una matriz con un solo elemento en lugar de múltiples elementos.
Mysticial
¿Por qué usar un StringBuffer? ¿Por qué convertir el entero a una cadena y luego a un entero y luego a un int y luego a un entero nuevamente? ¿Por qué usar una matriz con un solo elemento y por qué recorrer esa matriz de un solo elemento cuando contiene solo un elemento? ¿Por qué convertir los enteros a objetos en el bucle externo? Hay tantas preguntas aquí. ¿@CodeMadness es solo una cuenta troll?
Victor Zamanian
-5
Integer[] arr = (Integer[]) x.toArray(new Integer[x.size()]);

Acceso arrcomo normal int[].

snn
fuente
55
esto no responde a la pregunta, la pregunta era sobre la conversión al tipo primitivo (int)
Asaf