Introducción a las variables en Flutter: Las listas


Avatar de Pedro Cortez

Una clase de Flutter que será importante dominar para poder programar una aplicación es la clase List. ¿Cómo crear una lista, añadir elementos, eliminarlos, etc.? Intento responder a estas preguntas con ejemplos simples en este artículo.


clase flutter map

Crear una lista en Flutter

Como su nombre lo indica, las variables de tipo List te permiten crear listas, también conocidas como arrays en inglés. Estas estarán representadas por corchetes dentro de los cuales se separan los elementos con comas. Además, la lista tendrá un tipo que definirá el tipo de valores que podrá contener: String, int, bool, etc. Por ejemplo:

List<String> nombres = ["Pierre", "Paul", "Jacques"];
List<int> edades = [12, 37, 23, 17, 73];

Sin embargo, es posible crear listas llamadas dynamic, lo que significa que pueden contener varios tipos de datos. Por ejemplo:

List<dynamic> items = ["París", 9, true, TextEditingController(), MyNewWidget()];

De esta manera, puedes almacenar cualquier cosa en una clase List, siempre y cuando definas correctamente los valores que contendrá.

List.generate()

A veces, puede ser muy tedioso crear manualmente tu lista. Es en este caso que el método List<>.generate se vuelve útil. Este método te permite generar rápidamente listas de 1000 elementos o más. Aquí tienes un ejemplo:

var miLista = List<int>.generate(4, (int index) => index + 1, growable: true);
print(miLista);
↪ [1, 2, 3, 4]

Desglosémoslo. Aquí declaro una variable de tipo List<int> (mi lista contendrá números). Luego uso el método .generate para crear una lista con 4 elementos. Cada elemento será el resultado del cálculo de index + 1. El método comienza a contar desde 0, por lo que mi primer elemento será 1 + 0 = 1, luego 1 + 1 = 2, y así sucesivamente. Finalmente, growable tiene un valor de true, lo que significa que podré aumentar el tamaño de mi lista posteriormente agregando más elementos. Este comportamiento no será posible si growable tiene un valor de false.

El ejemplo aquí es muy simple, pero puedes usar métodos más complejos para tu lista. Por ejemplo, puedes pedir que en cada iteración se cree un nuevo color mediante un método y se añada a tu lista.

Lo principal que debes recordar es que debes indicar al principio la longitud de tu lista y que tu índice aumenta de 1 en cada iteración hasta alcanzar el límite que has establecido.

¿Cómo hago para que un elemento se agregue solo una vez de cada dos veces a mi lista?

Desafortunadamente, el método .generate no te permite realizar acciones diferentes según el índice. Sin embargo, puedes usar un bucle while() o if(), y cambiar la iteración, o realizar diferentes acciones según el índice.

Obtener una lista desde Firebase

Una de las ventajas de Firebase es que te permite almacenar tus listas en un documento. Por ejemplo, supongamos que has creado una aplicación de música y que las canciones favoritas de tus usuarios se almacenan en forma de lista. Puedes recuperar ese valor en el documento que te interesa, almacenarlo en una variable en el frontend y utilizarlo.

Para recuperar una lista en uno de tus documentos, tienes dos opciones:

  1. Abrir una instancia de Firestore, usar el método .get() y almacenar tu variable List en la parte superior de tu widget;
  2. Usar un StreamBuilder y crear tu variable List dentro de él (no siempre es deseable si no necesitas mostrar tu lista en la pantalla).

Aquí tienes un ejemplo de cómo recuperar una lista desde Firestore, utilizando la primera opción:

miLista = await FirebaseFirestore.instance
  .collection('Mi colección')
  .doc(id_del_doc)
  .get()
  .then((value) {
    return value.data()['Mi lista'];
  });

Aquí, mi función es asincrónica (porque lleva la palabra clave await delante). Esto significa que mi código se detendrá hasta que miLista obtenga un resultado. El cuerpo de mi función debe ser marcado como asincrónico colocando async al principio.

Manipular los elementos de tu variable List

Una vez que hayas creado tu lista, obviamente podrás recuperar los elementos que contiene, además de agregarlos, eliminarlos o modificarlos.

Los índices

Un concepto importante al hablar de listas es el índice. Un índice es un valor numérico que representa la posición de un elemento en una lista y te permite encontrarlo. Supongamos que tengo una lista de nombres ["Pierre", "Paul", "Jacques"] y quiero recuperar el primer nombre de mi lista. Podré encontrarlo utilizando su índice.

La particularidad de este sistema es que los índices no empiezan en 1, sino en 0. Por lo tanto, no encontraré el primer elemento de una lista con el índice 1, sino con el índice 0. Siempre es importante tener en cuenta este concepto, especialmente si utilizas la longitud de la lista para encontrar un elemento en particular. Por ejemplo, el último elemento de mi lista no estará en el índice n, sino en el índice n-1.

Encontrar el índice de un elemento

Para encontrar el índice de un elemento que se encuentra en tu lista, Flutter proporciona el método .indexOf(). Aquí tienes un ejemplo:

List letras = ['A', 'B', 'C', 'D'];
print(letras.indexOf('B'));
1

Si el método devuelve un valor de -1, significa que el elemento que estás buscando no existe en la lista.

Si un elemento aparece varias veces en la lista y quieres encontrar su último índice, puedes utilizar el método .lastIndexOf():

List letras = ['A', 'B', 'C', 'D', 'B'];
print(letras.lastIndexOf('B'));
4

Agregar un elemento

Para agregar un elemento a tu lista, solo necesitas usar el método .add(). Por ejemplo:

List<int> numeros = [0, 1, 2];
numeros.add(3);
print(numeros);
↪ [0, 1, 2, 3]

Para agregar varios elementos de una sola vez, puedes usar el método .addAll():

List<int> numeros = [0, 1, 2];
numeros.addAll({3, 4, 5});
print(numeros);
↪ [0, 1, 2, 3, 4, 5]

Los elementos se agregan al final de tu lista. Si deseas asignar un índice específico a un elemento, estarías haciendo una modificación en lugar de una adición.

Insertar un elemento

El método .insert() te permite insertar un nuevo elemento entre otros dos, en un índice dado:

List<int> numeros = [0, 2, 3];
int indice = 1;
numeros.insert(indice, 1);
print(numeros);
↪ [0, 1, 2, 3]

También existe el método .insertAll(), que te permite agregar varios elementos en posiciones específicas. Los elementos deben estar entre corchetes y separados por comas:

List<int> numeros = [0, 3];
List<int> nuevosNumeros = [1, 2];
numeros.insertAll(1, nuevosNumeros);
print(numeros);
↪ [0, 1, 2, 3]

Los elementos que insertes deben ser del mismo tipo que la lista. Por ejemplo, una lista de tipo int solo podrá contener números.

Modificar un elemento

La manera más simple de modificar un elemento existente en una lista es asignarle un nuevo valor. Por ejemplo:

List<int> numeros = [0, 1, 1, 3];
numeros[2] = 2;
print(numeros);
↪ [0, 1, 2, 3]

Sin embargo, también existe el método .replaceRange(), que te permite cambiar varios valores consecutivos en una lista de una sola vez. Solo necesitas indicar el índice de inicio, el de fin, y la lista de los nuevos elementos:

List<int> numeros = [0, 1, 2, 3];
numeros.replaceRange(2, 4, [4, 5]);
print(numeros);
↪ [0, 1, 4, 5]

Eliminar un elemento

Puedes eliminar un elemento de una lista utilizando el método .remove():

List<String> letras = ['A', 'B', 'C', 'D'];
letras.remove('B');
print(letras);
↪ [A, C, D]

Para eliminar un elemento utilizando su índice en lugar de su valor, deberás usar .removeAt():

List<String> letras = ['A', 'B', 'C', 'D'];
letras.removeAt(2);
print(letras);
↪ [A, B, D]

Puedes eliminar varios elementos consecutivos utilizando el método .removeRange():

List<String> letras = ['A', 'B', 'C', 'D'];
letras.removeRange(1, 3);
print(letras);
↪ [A, D]

El método .removeLast(), como su nombre indica, te permite eliminar el último valor contenido en la lista:

List<String> letras = ['A', 'B', 'C', 'D'];
letras.removeLast();
print(letras);
↪ [A, B, C]

Finalmente, .removeWhere() te permite eliminar todos los elementos de una lista que cumplan con un criterio. Por ejemplo:

List<int> numeros = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
numeros.removeWhere((item) => item % 2 == 0);
print(numeros);
↪ [1, 3, 5, 7, 9]

Mostrar una lista en pantalla

Por supuesto, las listas no solo están hechas para almacenarse en variables, también puedes mostrarlas en la pantalla. Para esto, puedes usar el widget ListView.

Los ListView son relativamente fáciles de usar y funcionan de manera similar a las columnas y filas. Tienen un parámetro children: [], que contendrá tus ListTile, es decir, los elementos de tu lista. Estos ListTile pueden ser generados a partir de variables de tipo List o creados manualmente como en este ejemplo:

ListView(
  children: const <Widget>[
    ListTile(
      title: Text('Elemento 1'),
    ),
    ListTile(
      title: Text('Elemento 2'),
    ),
    ListTile(
      title: Text('Elemento 3'),
    ),
  ],
),

Otros comandos de Flutter relacionados con las listas

A continuación, se presentan otros comandos que puedes usar con listas, los cuales podrían ser útiles para ti.

contains()

El método .contains() te permite saber si una lista contiene un elemento o no:

List<int> numeros = [0, 1, 2, 3]; 
print(numeros.contains(2));
true

isEmpty / isNotEmpty

Las propiedades isEmpty e isNotEmpty te permiten saber si tu lista contiene elementos o está vacía. Son particularmente útiles cuando deseas realizar dos acciones diferentes según el resultado:

List<int> numeros = []; 
if(numeros.isEmpty){
  print("La lista está vacía");
} else {
  print(numeros);
}
La lista está vacía

length

Como su nombre lo indica, la propiedad .length devuelve la longitud de tu lista. Por ejemplo:

List<int> numeros = [0, 1, 2, 3, 4, 5]; 
print(numeros.length);
6

forEach()

El método .forEach() te permite realizar una acción para cada elemento presente en tu lista:

List<int> numeros = [0, 1, 2, 3]; 
numeros.forEach((element){
  element = element + 1;
});
print(numeros);
1, 2, 3, 4

Esta acción no tiene que aplicarse necesariamente sobre el propio elemento. Por ejemplo, podrías sumar +1 a un contador por cada elemento en una lista. La idea clave es que .forEach() funciona como un bucle que recorre todos los elementos de la lista.

clear()

El método .clear(), como su nombre indica, limpia tu lista, es decir, elimina todos los valores que contiene:

List<int> numeros = [0, 1, 2, 3]; 
numeros.clear(); 
print(numeros);
↪ [] (lista vacía)

List.filled()

Una forma rápida de crear una lista que contenga varias veces el mismo elemento es usar el método List.filled():

final numeros = List.filled(5, "1");
print(numeros);
↪ [1, 1, 1, 1, 1]

shuffle()

El método .shuffle() mezcla aleatoriamente los valores dentro de tu lista:

List<int> numeros = [0, 1, 2, 3, 4, 5];
numeros.shuffle();
print(numeros);
↪ [2, 4, 1, 3, 5, 0]

sublist()

El método .sublist(), como su nombre indica, te permite crear una sublista de tu lista:

List<String> letras = ['A', 'B', 'C', 'D', 'E', 'F'];
List<String> nuevaLista = letras.sublist(1, 4);
print(nuevaLista);
↪ [B, C, D]

Conclusión

Ahora eres capaz de crear listas de elementos simples en Flutter. Pero, ¿cómo crear listas que contengan claves asociadas a valores? Te enseñaré todo eso en el próximo artículo:

Avatar de Pedro Cortez