Dart — Colecciones — Maps

2024-01-17T18:00:00-05:00 | 8 minutos de lectura | Actualizado en 2025-01-24T07:42:46-05:00

jaimetellezb
Dart — Colecciones — Maps

Tabla de Contenido

Introducción

Ya vimos tanto las listas como los conjuntos en Dart, además de sus constructores, propiedades y métodos que son compartidos entre ellos. Ahora veremos qué son los Mapas (Maps) y cómo se utilizan en Dart.

Mapas (Maps)

Los Maps son otro tipo de colección así como lo son los Lists y Sets, se puede decir que son similares a los Sets, solo que trabajar con llave (key) y valor (value), cada valor va asociado a una llave que designemos. Tanto las claves como los valores pueden ser de cualquier tipo, las claves son únicas pero los valores si se pueden repetir.

Constructores de mapas (Maps)

A continuación, veremos los constructores que se pueden utilizar en Dart para crear Mapas.

Se pueden crear Mapas (Maps) con literales o con métodos como veremos a continuación.

Literales

Crea un **Map** si especificar un constructor.

void main() {
  var colors = {
    2: 'red',
    10: 'green',
    18: 'blue',
  };

  print(colors); // {2: red, 10: green, 18: blue}
}

Constructor Map<K, V>

Crea un **Map** vacío.

// estructura del constructor
// Map<K, V>
// K: tipo de dato de la llave, V tipo de dato del valor

void main() {
  var letters = Map<int, String>();
  letters[0] = 'A';
  letters[1] = 'B';
  letters[2] = 'C';

  print(letters); // {0: A, 1: B, 2: C}
}

Constructor Map<K, V>.from

Crea un **Map** con las mismas claves y valores que el enviado como parámetro.

Es preferible utilizar Map.of siempre que sea posible, y sólo utilizar Map.from para crear un nuevo mapa con tipos más precisos que el original, y cuando se sepa que todas las claves y valores tienen esos tipos más precisos.

// estructura del constructor
// K: tipo de dato de la llave, V tipo de dato del valor
// other: Map con el que se va a crear otro.
Map<K, V>.from(
  Map other
)

// Ejemplo
void main() {
  var countries = {'COL': 'Colombia', 'BRA': 'Brasil', 'PTR': 'Portugal'};
  var countriesMap = Map<String, String>.from(countries);

  print(countriesMap); // {COL: Colombia, BRA: Brasil, PTR: Portugal}
}

Constructor Map<K, V>.fromEntries

Crea un nuevo **Map** y añade todas las entradas (los datos llave — valor enviados como parámetro). En caso de añadir más adelante otro valor con una llave existente, se reemplaza la el valor anterior con el nuevo.

// estructura del constructor
// K: tipo de dato de la llave, V tipo de dato del valor
// entries: iterable con entradas de Maps.
Map<K, V>.fromEntries(
  Iterable<MapEntry<K, V>> entries
)
void main() {
  var countries = <String, int>{'COL': 1, 'BRA': 3, 'PTR': 5};
  final fromEntriesMap = Map.fromEntries(countries.entries);
  fromEntriesMap.addAll(<String, int>{'COL': 3});

  print(fromEntriesMap); // {COL: 3, BRA: 3, PTR: 5}
}

Constructor Map<K, V>.fromIterable

Crea una instancia de **Map** en la que las claves y los valores se calculan a partir del iterable.

// estructura del constructor
// K: tipo de dato de la llave, V tipo de dato del valor

Map<K, V>.fromIterable(
  Iterable iterable,
{K key(
  dynamic element
)?,
V value(
  dynamic element
)?}
)

// ejemplo
void main() {
  final numbers = <int>[1, 2, 3, 4, 5];
  final map = Map.fromIterable(numbers);
  print(map); // {1: 1, 2: 2, 3: 3, 4: 4, 5: 5}
}

Constructor Map<K, V>.fromIterables

Crea un **Map** que asocia las claves dadas a los valores dados. Esto quiere decir que tanto sus llaves como sus valores se reciben por parámetros y con esto arma el **Map**.

// estructura del constructor
// K: tipo de dato de la llave, V tipo de dato del valor
// Iterable<K>: son las claves del nuevo Map.
// Iterable<V>: son los valores del nuevo Map.
Map<K, V>.fromIterables(
  Iterable<K> keys,
  Iterable<V> values
)

// Ejemplo
void main() {
  final values = <bool>[true, false, false, true];
  final keys = <String>{'Apple', 'Lemon', 'Cherry', 'Pear'};
  final map = Map<String, bool>.fromIterables(keys, values);
  print(map); // {Apple: true, Lemon: false, Cherry: false, Pear: true}
}

Constructor Map<K, V>.identity

Crea un mapa de identidad con la implementación por defecto.

// estructura del constructor
// K: tipo de dato de la llave, V tipo de dato del valor
Map<K, V>.identity()

// ejemplo
void main() {
  var identityMap = Map.identity();
  identityMap.addAll({'Apple': true, 'Cherry': false});
  print(identityMap); // {Apple: true, Cherry: false}
}

Constructor Map<K, V>.of

Crea un **Map** con las mismas claves y valores que el enviado por parámetro. Este constructor es recomendable sobre el Map.from.

// estructura del constructor
// K: tipo de dato de la llave, V tipo de dato del valor
// other: Map con el que se va a crear otro.
Map<K, V>.of(
  Map<K, V> other
)

// ejemplo
void main() {
  final animals = <int, String>{1: 'Lion', 2: 'Tiger', 3: 'Monkey'};
  final mapOf = Map<num, String>.of(animals);
  print(mapOf); // {1: Lion, 2: Tiger, 3: Monkey}
}

Constructor Map<K, V>.unmodifiable

Crea un mapa no modificable basado en hash que contiene las entradas del **Map** recibido por parámetro.

// estructura del constructor
// K: tipo de dato de la llave, V tipo de dato del valor
// other: Map con el que se va a crear otro.
Map<K, V>.unmodifiable(
  Map other
)

// ejemplo
void main() {
  final animals = <int, String>{1: 'Lion', 2: 'Tiger', 3: 'Monkey'};
  final unmodifiableMap = Map.unmodifiable(animals);
  // Uncaught Error: Unsupported operation: Cannot modify unmodifiable map
  unmodifiableMap[4] = 'Bee';
}

Propiedades de un Mapa (Map)

Veremos a continuación, las propiedades que traen los **Maps** en Dart.

void main() {

  final animals = <int, String>{1: 'Lion', 2: 'Tiger', 3: 'Monkey', 4: 'Bee'};

  // entries → Iterable<MapEntry<K, V>>
  // obtiene las entradas del mapa.
  // (MapEntry(1: Lion), MapEntry(2: Tiger), MapEntry(3: Monkey), MapEntry(4: Bee))
  print(animals.entries);

  // hashCode → int
  // obtiene el identificador hash para el Map. Cambia por cada ejecución.
  print(animals.hashCode);

  // isEmpty → bool
  // Valida si el Map está vació.
  print(animals.isEmpty); // true o false

  // isNotEmpty → bool
  // Valida si el Map tiene al menos un par clave/valor.
  print(animals.isNotEmpty); // true o false

  // keys → Iterable<K>
  // obtiene las llaves del Map. como Iterable.
  print(animals.keys); // (1, 2, 3, 4)

  // length → int
  // devuelve el tamaño del Map.
  print(animals.length); // 4

  // runtimeType → Type
  // devuelve el tipo de objeto en tiempo de ejecución.
  print(animals.runtimeType); // JsLinkedHashMap<int, String>

  // values → Iterable<V>
  // obtiene los valores del Map. como Iterable.
  print(animals.values); // (Lion, Tiger, Monkey, Bee)

}

Métodos de un Mapa (Map)

A continuación, los métodos que podemos utilizar con los **Maps**.

void main() {

  final animals = <int, String>{1: 'Lion', 2: 'Tiger', 3: 'Monkey', 4: 'Bee'};

  // addAll(Map<K, V> other) → void
  // Agrega más pares llave/valor al Map.
  // Si la clave ya existe en el mapa se sobreescribe el valor.
  animals.addAll({4: 'Spider', 5: 'Eagle'});
  print(animals); // {1: Lion, 2: Tiger, 3: Monkey, 4: Spider, 5: Eagle}

  // addEntries(Iterable<MapEntry<K, V>> newEntries) → void
  // Agrega todos los pares clave/valor de newEntries en animals.
  final newEntries = <int, String>{6: 'Bee'};
  animals.addEntries(newEntries.entries);
  print(animals); // {1: Lion, 2: Tiger, 3: Monkey, 4: Spider, 5: Eagle, 6: Bee}

  // cast<RK, RV>() → Map<RK, RV>
  // provee una vist del Map.
  print(animals.cast()); // {1: Lion, 2: Tiger, 3: Monkey, 4: Spider, 5: Eagle, 6: Bee}

  // clear() → void
  // elimina todos los pares del Map.
  animals.clear();
  print(animals); // {}

  final newAnimals = <int, String>{1: 'Lion', 2: 'Tiger', 3: 'Monkey', 4: 'Bee'};

  // containsKey(Object? key) → bool
  // busca el par por medio de la clave, si existe true, sino false.
  print(newAnimals.containsKey(4)); // true

  // containsValue(Object? value) → bool
  // busca el par por medio del valor, si existe true, sino false.
  print(newAnimals.containsValue('Tiger')); // true

  // forEach(void action(K key, V value)) → void
  // Se recorren todos los pares clave/valor.
  newAnimals.forEach((key, value) => print('$key - $value'));
  // 1 - Lion
  // 2 - Tiger
  // 3 - Monkey
  // 4 - Bee

  // map<K2, V2>(MapEntry<K2, V2> convert(K key, V value)) → Map<K2, V2>
  // Devuelve un nuevo mapa donde todas las entradas de este mapa
  // se transforman mediante la función de conversión dada.

  // noSuchMethod(Invocation invocation) → dynamic
  // Se invoca cuando se accede a un método o propiedad inexistente.

  // putIfAbsent(K key, V ifAbsent()) → V
  // Busca el valor de la clave o agregue una nueva entrada si no está allí.
  print(newAnimals.putIfAbsent(4, () => 'New')); // Bee

  // remove(Object? key) → V?
  // Elimina clave y valor asociados a la clave ingresada.
  print(newAnimals.remove(4)); // Bee
  print(newAnimals); // {1: Lion, 2: Tiger, 3: Monkey}

  // removeWhere(bool test(K key, V value)) → void
  // Elimina clave y valor cuando se cumple la condición.
  newAnimals.removeWhere((key, value) => key > 2);
  print(newAnimals); // {1: Lion, 2: Tiger}

  // toString() → String
  // devuelve una representación de string.
  print(newAnimals.toString()); // {1: Lion, 2: Tiger}

  // update(K key, V update(V value), {V ifAbsent()?}) → V
  // Actualiza el valor de la clave proporcionada.
  // Devuelve el nuevo valor asociado con la clave.
  // Si la clave está presente, invoca la actualización con el valor actual y
  // almacena el nuevo valor en el mapa. Si la clave no está presente
  // y se proporciona ifAbsent, llama a ifAbsent y agrega la clave con el valor devuelto
  // al mapa. Si la clave no está presente, se debe proporcionar ifAbsent.
  print(newAnimals..update(1, (value) => 'Bee')); // {1: Bee, 2: Tiger}
  print(newAnimals..update(3, (value) => 'Lion', ifAbsent: () => 'Spider'));
  // {1: Bee, 2: Tiger, 3: Spider}

  // updateAll(V update(K key, V value)) → void
  // Actualiza todos los valores teniendo en cuenta la función que se pasa.
  newAnimals..updateAll((key, value) => value.toUpperCase());
  print(newAnimals); // {1: BEE, 2: TIGER, 3: SPIDER}
}

Conclusión

Podemos concluir el tema de las colecciones en Dart, vimos un poco a profundidad los constructores, propiedades y métodos de las 3 colecciones que nos da soporte Dart, ya depende de cada caso saber cuál es la mejor opción para utilizar.

¡Gracias por leer!

Fuentes

© 2022 - 2025 jaimetellezb - Compartir guías y tutoriales de programación.

🌱 Powered by Hugo with theme Dream.

Sobre mí

alt

Ingeniero de software

Hola, bienvenidos a mi blog sobre guías y tutoriales de programación.

Aquí podrás encontrar guías y tutoriales sobre algunos temas de tecnología en general. La idea es poder ayudar a que ciertas cosas como configuraciones de nuevas herramientas sean más fáciles de abordar y utilizar. También pequeños proyectos donde se usen diferentes tecnologías como ejemplo.

Enlaces sociales