¿Crear lista mutable desde matriz?

84

Tengo una matriz que me gustaría convertir en una Listpara modificar el contenido de la matriz.

Desbordamiento de la pila tiene un montón de preguntas / respuestas que la dirección Arrays.asList()y la forma en que sólo proporciona una vista de lista de la matriz subyacente, y cómo tratar de manipular la lista resultante generalmente lanzar una UnsupportedOperationExceptioncomo los métodos utilizados para manipular la lista (por ejemplo add(), remove(), etc.) son no implementado por la implementación de List proporcionada por Arrays.asList().

Pero no puedo encontrar un ejemplo de cómo convertir una matriz en una Lista mutable. Supongo que puedo recorrer la matriz y put()cada valor en una nueva Lista, pero me pregunto si existe una interfaz para hacer esto por mí.

ericsoco
fuente

Respuestas:

122

Una forma sencilla:

Foo[] array = ...;
List<Foo> list = new ArrayList<Foo>(Arrays.asList(array));

Eso creará una lista mutable, pero será una copia de la matriz original. Cambiar la lista no cambiará la matriz. Puede copiarlo más tarde, por supuesto, usando toArray.

Si desea crear una vista mutable en una matriz, creo que tendrá que implementarla usted mismo.

Jon Skeet
fuente
2
Arrays.asList devuelve una vista en una matriz, con esos métodos mutantes admitidos que no afectan el tamaño de la lista
Timo Westkämper
1
@ jon-skeet Lo sé, solo estaba diciendo que Arrays.asList le brinda una lista respaldada por una matriz con mutabilidad limitada, si necesita agregar / eliminar / insertar, entonces la envoltura de ArrayList es un mejor enfoque.
Timo Westkämper
4
Java necesita dejar clara la mutabilidad / inmutabilidad en todos estos métodos de fábrica estáticos. Es un fastidio descubrir que hiciste algo inmutable en tiempo de ejecución.
dustinevan
1
@dustinevan: La documentación es bastante clara OMI: "Devuelve una lista de tamaño fijo respaldada por la matriz especificada. (Los cambios en la lista devuelta" escriben "en la matriz)"
Jon Skeet
1
@JonSkeet no quiere perder su tiempo, gracias por todo lo que hace. Solo me gustaría votar para obtener más claridad en los nombres, estoy seguro de que los documentos son claros. Algunos de nosotros bailamos entre idiomas, y esto es bastante claro en otros idiomas.
dustinevan
21

Y si está utilizando las API de colección de Google

Lists.newArrayList(myArray)
vsingh
fuente
1
Ésta es la respuesta más concisa. Gracias.
eugene82
2
Incluso la propia Guava recomienda usar cualquiera de new ArrayList<>(Arrays.asList(...))los dos : el javadoc para el método implica que quedará obsoleto porque no es lo suficientemente útil.
Recogida de Logan
2020 y aún no está en desuso. ¡Súbete!
markthegrea hace
11

Este código simple que usa la API Stream incluida en Java 8 crea una lista mutable (o vista) que contiene los elementos de su matriz:

Foo[] array = ...;
List<Foo> list = Stream.of(array).collect(Collectors.toCollection(ArrayList::new));

O, igualmente válido:

List<Foo> list = Arrays.stream(array).collect(Collectors.toCollection(ArrayList::new));
MikaelF
fuente
4

Si está usando Eclipse Collections (anteriormente GS Collections ), puede usar FastList.newListWith(...)o FastList.wrapCopy(...).

Ambos métodos toman varargs, por lo que puede crear la matriz en línea o pasar una matriz existente.

MutableList<Integer> list1 = FastList.newListWith(1, 2, 3, 4);

Integer[] array2 = {1, 2, 3, 4};
MutableList<Integer> list2 = FastList.newListWith(array2);

La diferencia entre los dos métodos es si la matriz se copia o no. newListWith()no copia la matriz y, por lo tanto, lleva un tiempo constante. Debe evitar usarlo si sabe que la matriz podría estar mutada en otro lugar.

Integer[] array2 = {1, 2, 3, 4};
MutableList<Integer> list2 = FastList.newListWith(array2);
array2[1] = 5;
Assert.assertEquals(FastList.newListWith(1, 5, 3, 4), list2);

Integer[] array3 = {1, 2, 3, 4};
MutableList<Integer> list3 = FastList.wrapCopy(array3);
array3[1] = 5;
Assert.assertEquals(FastList.newListWith(1, 2, 3, 4), list3);

Nota: Soy un comprometido con las colecciones de Eclipse.

Craig P. Motlin
fuente
1
Esa es una buena API de colecciones que tienes allí. El primero que he visto que podría tentarme a alejarme de mis propias implementaciones ... lo único que parece faltar y que encuentro generalmente útil es una implementación de conjunto ordenada respaldada por una matriz (que encuentro que es mucho más eficiente que una implementación basada en árbol para datos que rara vez se modifican o para conjuntos que pueden modificarse con frecuencia pero que por lo general contienen menos de 10 o más elementos).
Jules
0
myNewArrayList = new ArrayList<>(Arrays.asList(myArray));
Sid
fuente
1
@JonSkeet sé que su comentario es de 2012, y estoy viviendo en el futuro ahora, pero supongo que este comentario no se ha mantenido bien considerando que mi IDE subraya específicamente y dice "oye, no declares esto con un tipo declarado. No lo necesita allí "?
Brent Thoenen
1
@BrentThoenen: No entiendo tu comentario. ¿Notaste que mi comentario se refería a la revisión 1, que usaba myNewArrayList = new ArrayList(...), es decir, el tipo sin formato? Hay una diferencia entre "usar el operador de diamante para permitir que el compilador desarrolle un argumento de tipo" y "usar un tipo sin formato".
Jon Skeet
1
Publiqué esta respuesta y viví en el olvido todo este tiempo que @JonSkeet mismo comentó mi respuesta. Gracias Brent por comentar.
Sid
@JonSkeet ahh, mi culpa. No revisé la revisión que comentabas. Hice una suposición incorrecta en que 2012 Java asumió que el operador de diamante vacío también era un tipo sin formato. Esa es mi b. ¡gracias por la respuesta!
Brent Thoenen
0

Agregando otra opción usando Streams API:

List<Foo> list = Arrays.stream(array).collect(Collectors.toList());
Sahil Chhabra
fuente
2
El problema con su solución es que Collectors # toList no tiene garantía de mutabilidad y, por lo tanto, no cumple con los requisitos.
MikaelF