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'
};
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.
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 ( ' \n Recorrido 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 ( ' \n Imprimir 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 ( ' \n Recorrido 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 ( ' \n Imprimir con ForEach' );
usuario. forEach ((llave, valor){
print ( ' $ llave : $ valor ' );
});
}
Common Map Operations
Operation Method Description Example Add/Update map[key] = valueAdds or updates entry telefonos['Ana'] = '123'Search containsKey(key)Check if key exists telefonos.containsKey('Juan')Access map[key]Get value by key telefonos['Juan']Iterate forEach()Loop through entries map.forEach((k, v) => ...)Remove remove(key)Delete entry telefonos.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
Strongly Typed Maps (Recommended)
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);
// Get only active users
Map < String , dynamic > activeUsers = Map . fromEntries (
usuarios.entries. where ((entry) => entry.value[ 'activo' ] == true )
);
Best Practices
Use appropriate types : Choose Map<String, int> over Map<String, dynamic> when possible
Check before access : Always use containsKey() or null-aware operators
Use forEach() for iteration : It’s more concise and readable than manual loops
Meaningful keys : Use descriptive key names that represent the data
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.