Skip to main content

Advanced Map Structures

Maps can contain complex data types, including lists as values. This allows you to create sophisticated data structures for real-world applications.

Maps with List Values

You can create maps where each key maps to a list of values:
Map<String, List<int>> calificacionesPorMateria = {
  'Matemáticas'   : [85, 90, 88],
  'Español'       : [92, 88, 95],
  'Inglés'        : [78, 82, 80],
  'Programación'  : [95, 98, 96]
};
The syntax Map<String, List<int>> means each key (String) maps to a list of integers. This is perfect for storing multiple values per category.

Real-World Example: Grade Management System

Let’s build a complete grade management system that:
  • Calculates the average for each subject
  • Finds the best and worst performing subjects
  • Generates a comprehensive report

Calculating Subject Averages

void promedioMateria(Map<String, List<int>> calificacionesPorMateria, Map<String, double> promedios){
  // Calcula el promedio de cada materia
  calificacionesPorMateria.forEach((materia, calificaciones){
    int suma = 0;
    for (var calificacion in calificaciones) {
      suma += calificacion;
    }
    double promedio = suma / calificaciones.length;
    promedios[materia] = promedio;
  });
}
This function takes two maps: one for input (grades) and one for output (averages). This pattern keeps data organized and functions focused.

Finding the Best Subject

void obtenerMejorPromedio(Map<String, double> promedios) {
  // Encuentra la materia con el mejor promedio
  double mejorPromedio = 0.0;
  String mejorMateria = '';
  promedios.forEach((materia, promedio){
    if (promedio > mejorPromedio) {
      mejorPromedio = promedio;
      mejorMateria = materia;
    }
  });
  print('\nMATERIA CON MEJOR PROMEDIO: $mejorMateria');
}

Finding the Worst Subject

void obtenerPeorPromedio(Map<String, double> promedios) {
  // Encuentra la materia con el peor promedio
  double peorPromedio = 100.0;
  String peorMateria = '';
  promedios.forEach((materia, promedio){
    if (promedio < peorPromedio) {
      peorPromedio = promedio;
      peorMateria = materia;
    }
  });
  print('\nMATERIA CON PEOR PROMEDIO: $peorMateria');
}
We initialize peorPromedio to 100.0 (the maximum possible grade) to ensure any actual grade will be lower.

Generating Reports

void reporteCompleto(Map<String, List<int>> calificacionesPorMateria) {
  // Imprime reporte completo
  print('\n==== MATERIAS CON SUS CALIFICACIONES ====');
  calificacionesPorMateria.forEach((materia, calificaciones){
    print('Materia: $materia \t- \t$calificaciones');
  });
  print('');
}

void imprimirPromedios(Map<String, double> promedios) {
  print('\n==== MATERIAS CON SUS PROMEDIOS ====');
  promedios.forEach((materia, promedio){
    print('Materia: $materia \t- ${promedio.toStringAsFixed(2)}');
  });
  print('');
}
Use toStringAsFixed(2) to format decimal numbers to 2 decimal places for cleaner output.

Complete Working Example

void promedioMateria(Map<String, List<int>> calificacionesPorMateria, Map<String, double> promedios){
  calificacionesPorMateria.forEach((materia, calificaciones){
    int suma = 0;
    for (var calificacion in calificaciones) {
      suma += calificacion;
    }
    double promedio = suma / calificaciones.length;
    promedios[materia] = promedio;
  });
}

void obtenerMejorPromedio(Map<String, double> promedios) {
  double mejorPromedio = 0.0;
  String mejorMateria = '';
  promedios.forEach((materia, promedio){
    if (promedio > mejorPromedio) {
      mejorPromedio = promedio;
      mejorMateria = materia;
    }
  });
  print('\nMATERIA CON MEJOR PROMEDIO: $mejorMateria');
}

void obtenerPeorPromedio(Map<String, double> promedios) {
  double peorPromedio = 100.0;
  String peorMateria = '';
  promedios.forEach((materia, promedio){
    if (promedio < peorPromedio) {
      peorPromedio = promedio;
      peorMateria = materia;
    }
  });
  print('\nMATERIA CON PEOR PROMEDIO: $peorMateria');
}

void reporteCompleto(Map<String, List<int>> calificacionesPorMateria) {
  print('\n==== MATERIAS CON SUS CALIFICACIONES ====');
  calificacionesPorMateria.forEach((materia, calificaciones){
    print('Materia: $materia \t- \t$calificaciones');
  });
  print('');
}

void imprimirPromedios(Map<String, double> promedios) {
  print('\n==== MATERIAS CON SUS PROMEDIOS ====');
  promedios.forEach((materia, promedio){
    print('Materia: $materia \t- ${promedio.toStringAsFixed(2)}');
  });
  print('');
}

void main() {
  Map<String, List<int>> calificacionesPorMateria = {
    'Matemáticas'   : [85, 90, 88],
    'Español'       : [92, 88, 95],
    'Inglés'        : [78, 82, 80],
    'Programación'  : [95, 98, 96]
  };

  Map<String, double> promedios = {};

  promedioMateria(calificacionesPorMateria, promedios);
  imprimirPromedios(promedios);
  obtenerMejorPromedio(promedios);
  obtenerPeorPromedio(promedios);
  reporteCompleto(calificacionesPorMateria);
}
Sample Output:
==== MATERIAS CON SUS PROMEDIOS ====
Materia: Matemáticas 	- 87.67
Materia: Español 	- 91.67
Materia: Inglés 	- 80.00
Materia: Programación 	- 96.33

MATERIA CON MEJOR PROMEDIO: Programación

MATERIA CON PEOR PROMEDIO: Inglés

==== MATERIAS CON SUS CALIFICACIONES ====
Materia: Matemáticas 	- 	[85, 90, 88]
Materia: Español 	- 	[92, 88, 95]
Materia: Inglés 	- 	[78, 82, 80]
Materia: Programación 	- 	[95, 98, 96]

Complex Map Structures

StructureTypeUse CaseExample
Simple MapMap<String, int>Single valuesAges, IDs
List ValuesMap<String, List<int>>Multiple values per keyGrades, scores
Nested MapsMap<String, Map<String, int>>Hierarchical dataCategories with subcategories
Dynamic MapsMap<String, dynamic>Mixed typesJSON data, API responses

Common Patterns with Complex Maps

Pattern 1: Aggregate Data

Calculate statistics from lists in maps:
map.forEach((key, values) {
  double average = values.reduce((a, b) => a + b) / values.length;
  print('$key: $average');
});

Pattern 2: Find Extremes

Find maximum or minimum values:
double maxValue = 0;
String maxKey = '';
map.forEach((key, value) {
  if (value > maxValue) {
    maxValue = value;
    maxKey = key;
  }
});

Pattern 3: Transform Data

Convert one map structure to another:
Map<String, double> transformed = {};
original.forEach((key, list) {
  transformed[key] = calculateSomething(list);
});

Pattern 4: Filter and Report

Generate reports based on conditions:
map.forEach((key, value) {
  if (value > threshold) {
    print('$key exceeds threshold: $value');
  }
});

Real-World Applications

Student Records

Track multiple grades per subject for each student

Sales Data

Store daily sales figures for each product or region

Inventory Management

Track multiple warehouses with stock levels per item

Analytics

Collect and analyze time-series data by category

Advanced Techniques

Using reduce() for Calculations

int suma = calificaciones.reduce((a, b) => a + b);

Sorting Map Entries

var sortedEntries = promedios.entries.toList()
  ..sort((a, b) => b.value.compareTo(a.value));

Creating Maps from Lists

Map<String, int> countMap = {};
for (var item in list) {
  countMap[item] = (countMap[item] ?? 0) + 1;
}

Performance Considerations

When working with large maps containing lists:
  • Avoid unnecessary iterations through all data
  • Cache calculated values instead of recalculating
  • Consider using separate maps for different views of the data
For better organization:
  • Separate data processing into small, focused functions
  • Use descriptive function names that explain what they do
  • Keep data structures and their transformations clear and documented

Best Practices

  1. Separate concerns: Create different maps for raw data vs. calculated results
  2. Validate data: Check for empty lists before calculating averages
  3. Use meaningful names: Choose clear variable names like calificacionesPorMateria
  4. Format output: Use toStringAsFixed() for consistent number formatting
  5. Modular functions: Break complex operations into smaller, reusable functions

Error Handling

void promedioMateria(Map<String, List<int>> calificacionesPorMateria, Map<String, double> promedios){
  calificacionesPorMateria.forEach((materia, calificaciones){
    if (calificaciones.isEmpty) {
      print('Warning: $materia has no grades');
      return;
    }
    int suma = 0;
    for (var calificacion in calificaciones) {
      suma += calificacion;
    }
    double promedio = suma / calificaciones.length;
    promedios[materia] = promedio;
  });
}
Always check if lists are empty before performing calculations to avoid division by zero or other errors.

Build docs developers (and LLMs) love