Skip to main content

Working with Maps

This guide explores practical map operations through real-world examples including phone directories and user profiles.

Basic Map Operations: Phone Directory

Let’s create a phone directory using a map:
Map<String, String> telefonos = {
  'Juan': '8764521111',
  'María': '8764521222'
};

Searching for Contacts

Check if a contact exists before accessing it:
if (telefonos.containsKey('Juan')) {
  print('Teléfono de Juan: ${telefonos['Juan']}');
} else {
  print('Contacto No Existe!!!!');
}
Always use containsKey() to verify a key exists before accessing it to avoid null values.

Adding Contacts Dynamically

You can add new entries to a map after creation:
import 'dart:io';

String nombre = '';
for (var i = 0; i < 3; i++) {
  print('Nombre del Contacto:');
  nombre = stdin.readLineSync()!;
  print('Número de Telefono de $nombre:');
  telefonos[nombre] = stdin.readLineSync()!;
}

Iterating Through Maps

Use the forEach() method to iterate through all key-value pairs:
print('\nRecorrido de un Diccionario:');
telefonos.forEach((clave, valor){
  print('$clave: $valor');
});
Output:
Recorrido de un Diccionario:
Juan: 8764521111
María: 8764521222
Pedro: 8764523333
The forEach() method takes a function with two parameters: the key and the value.

Maps with Dynamic Values

Maps can store different types of values using the dynamic type:
Map<String, dynamic> usuario = {
  'nombre': 'Roberto',
  'edad': 20,
  'activo': true,
  'calificacion': 8.5
};

Accessing Different Types

print(usuario['nombre']); // Roberto (String)
print(usuario['edad']);  // 20 (int)
print(usuario['activo']); // true (bool)
print(usuario['calificacion']); // 8.5 (double)
When using dynamic, Dart can’t check types at compile time. Be careful when accessing values to avoid runtime errors.

Iterating Dynamic Maps

Use forEach() with dynamic maps just like regular maps:
print('\nImprimir con ForEach');
usuario.forEach((llave, valor){
  print('$llave: $valor');
});
Output:
Imprimir con ForEach
nombre: Roberto
edad: 20
activo: true
calificacion: 8.5

Complete Examples

Example 1: Phone Directory

import 'dart:io';

void main() {
  Map<String, String> telefonos = {
    'Juan': '8764521111',
    'María': '8764521222'
  };

  // Buscar
  if (telefonos.containsKey('Juan')) {
    print('Teléfono de Juan: ${telefonos['Juan']}');
  } else 
    print('Contacto No Existe!!!!');

  //Agregar Datos al Diccionario
  String nombre = '';
  for (var i = 0; i < 3; i++) {
    print('Nombre del Contacto:');
    nombre = stdin.readLineSync()!;
    print('Número de Telefono de $nombre:');
    telefonos[nombre] = stdin.readLineSync()!;
  }

  // Iterar
  print('\nRecorrido de un Diccionario:');
  telefonos.forEach((clave, valor){
    print('$clave: $valor');
  });
  print('');
  
}

Example 2: User Profile

void main() {
  Map<String, dynamic> usuario = {
    'nombre': 'Roberto',
    'edad': 20,
    'activo': true,
    'calificacion': 8.5
  };

  print(usuario['nombre']); // Roberto
  print(usuario['edad']);  // 20
  print(usuario['activo']); // true
  print(usuario['calificacion']); // 8.5

  print('\nImprimir con ForEach');
  usuario.forEach((llave, valor){
    print('$llave: $valor');
  });
}

Common Map Operations

OperationMethodDescriptionExample
Add/Updatemap[key] = valueAdds or updates entrytelefonos['Ana'] = '123'
SearchcontainsKey(key)Check if key existstelefonos.containsKey('Juan')
Accessmap[key]Get value by keytelefonos['Juan']
IterateforEach()Loop through entriesmap.forEach((k, v) => ...)
Removeremove(key)Delete entrytelefonos.remove('Juan')

Iteration Methods Comparison

Method 1: forEach()

Best for simple iteration:
map.forEach((key, value) {
  print('$key: $value');
});

Method 2: for-in with keys

When you need more control:
for (var key in map.keys) {
  print('$key: ${map[key]}');
}

Method 3: entries

When you need both key and value as objects:
for (var entry in map.entries) {
  print('${entry.key}: ${entry.value}');
}

Use Cases for Different Map Types

String to String

Phone directories, translations, configuration settings

String to int

Ages, scores, quantities, IDs

String to dynamic

User profiles, JSON-like data, flexible configurations

int to String

Error codes to messages, ID to name mappings

Type Safety Considerations

Map<String, int> ages = {'Alice': 25, 'Bob': 30};
int aliceAge = ages['Alice']!; // Type safe
Use strongly typed maps when all values are the same type for better type safety and IDE support.

Dynamic Maps (Use with Caution)

Map<String, dynamic> user = {'name': 'Alice', 'age': 25};
String name = user['name'] as String; // Need type casting
int age = user['age'] as int;
With dynamic maps, you lose compile-time type checking and need to cast values. Use only when necessary (e.g., JSON parsing).

Practical Patterns

Pattern 1: Safe Access with Default Value

String phone = telefonos['Unknown'] ?? 'No phone available';

Pattern 2: Conditional Update

if (!telefonos.containsKey('Pedro')) {
  telefonos['Pedro'] = '8764525555';
}

Pattern 3: Bulk Operations

Map<String, String> newContacts = {
  'Ana': '111111',
  'Luis': '222222'
};
telefonos.addAll(newContacts);

Pattern 4: Filter and Transform

// Get only active users
Map<String, dynamic> activeUsers = Map.fromEntries(
  usuarios.entries.where((entry) => entry.value['activo'] == true)
);

Best Practices

  1. Use appropriate types: Choose Map<String, int> over Map<String, dynamic> when possible
  2. Check before access: Always use containsKey() or null-aware operators
  3. Use forEach() for iteration: It’s more concise and readable than manual loops
  4. Meaningful keys: Use descriptive key names that represent the data
  5. Handle null values: Maps return null for non-existent keys, so handle this appropriately
Remember: Map keys must be unique, but values can repeat. If you add an existing key, it will update the value, not create a duplicate.

Build docs developers (and LLMs) love