codestory

Die Anleitung zu Dart Map

  1. Map<K,V>
  2. Constructors
  3. Properties
  4. Methods
  5. addAll(Map<K, V> other)
  6. addEntries(..)
  7. cast<RK, RV>()
  8. castFrom<K, V, K2, V2>(..)
  9. clear()
  10. containsKey(Object? key)
  11. containsValue(Object? value)
  12. forEach(..)
  13. putIfAbsent(..)
  14. remove(Object? key)
  15. removeWhere(..)
  16. update(..)
  17. updateAll(..)

1. Map<K,V>

In der Dart-Sprache stellt die Klasse Map<K,V> eine Datenstruktur dar, die aus Zuordnungen zwischen Schlüsseln und Werten besteht. Die Schlüssel können nicht dupliziert werden und jeder Schlüssel entspricht einem Wert.
Als typisches Beispiel sei hier ein Telefonbuch genannt. Die Telefonnummer ist der Schlüssel und der Besitzername der Telefonnummer ist ein Wert.
map_ex1.dart
void main() {
  Map<String, String> phonebook =  {
    '01000005': 'Tom',
    '01000002': 'Jerry',
    '01000003': 'Tom',
    '01000004': 'Donald'
  };
  Iterable<String> phoneNumbers = phonebook.keys;

  for (var phoneNumber in phoneNumbers) {
    String? name = phonebook[phoneNumber];
    print('Phone Number: $phoneNumber ==> Name: $name');
  }
  print(' ------------- ');
  var phoneNumber = '99999999';
  String? name = phonebook[phoneNumber];
  print('Phone Number: $phoneNumber ==> Name: $name');
}
Output:
Phone Number: 01000005 ==> Name: Tom
Phone Number: 01000002 ==> Name: Jerry
Phone Number: 01000003 ==> Name: Tom
Phone Number: 01000004 ==> Name: Donald
 -------------
Phone Number: 99999999 ==> Name: null
Die Klassenhierarchie der Map-Gruppe:
  • LinkedHashMap

2. Constructors

Die Konstructor:
external factory Map();
factory Map.from(Map other) = LinkedHashMap<K, V>.from;
factory Map.of(Map<K, V> other) = LinkedHashMap<K, V>.of;
external factory Map.unmodifiable(Map<dynamic, dynamic> other);
factory Map.identity() = LinkedHashMap<K, V>.identity;  

factory Map.fromIterable(Iterable iterable,
             {K key(dynamic element)?, V value(dynamic element)?}) = LinkedHashMap<K, V>.fromIterable;  
    
factory Map.fromIterables(Iterable<K> keys, Iterable<V> values) = LinkedHashMap<K, V>.fromIterables;
factory Map.fromEntries(Iterable<MapEntry<K, V>> entries) =>  <K, V>{}..addEntries(entries);
Map()
external factory Map();
Erstellts ein leeres LinkedHashMap .
Map.from(Map other)
factory Map.from(Map other) = LinkedHashMap<K, V>.from;
Erstellt eine LinkedHashMap mit allen von other importierten Mappings.
Dieser Konstruktor überprüft nicht den Datentyp des other, sodass zur Laufzeit der Anwendung ein Fehler auftreten kann. Sie sollten nach Möglichkeit lieber den Konstruktor Map.of verwenden.
Zum Beispiel:
map_from_ex1.dart
void main()  {
  Map<String, dynamic> other = {
    'A' : 'A1',
    'B' : 'B1',
    'C' : 100  // ---> int type !!!!!!!
  };
  Map<String,String> map = Map.from(other); // Compile OK, but throw Error at runtime!
  print(map); 
}
Output:
Unhandled exception:
type 'int' is not a subtype of type 'String' in type cast
#0      new LinkedHashMap.from.<anonymous closure> (dart:collection/linked_hash_map.dart:88:26)
#1      _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:397:8)
#2      new LinkedHashMap.from (dart:collection/linked_hash_map.dart:87:11)
#3      main
bin/map_from_ex1.dart:7
#4      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:283:19)
#5      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
Map.of(Map<K, V> other)
factory Map.of(Map<K, V> other) = LinkedHashMap<K, V>.of;
Erstellt eine LinkedHashMap mit allen von other importierten Mappings.
Map.identity()
factory Map.identity() = LinkedHashMap<K, V>.identity;
Gibt eine "Identity Map" zurück, bei der es sich um eine Map handelt, die hashcode und die Funktion identical verwendet, um zwei Schlüssel zu vergleichen. (Weitere Erläuterungen finden Sie im Artikel).
  • Dart LinkedHashMap
Map.unmodifiable(..)
external factory Map.unmodifiable(Map<dynamic, dynamic> other);
Erstellt ein nicht änderbares Objekt Map, bei dem alle Mappings von other importiert werden.
Map.fromIterable(..)
factory Map.fromIterable(Iterable iterable,
             {K key(dynamic element)?, V value(dynamic element)?}) = LinkedHashMap<K, V>.fromIterable;
Erstellt ein Objekt Map mit Schlüsseln und Werten, die aus den Elementen eines angegebenen Iterable berechnet werden.
map_fromIterable_ex1.dart
void main()  {
  var iterable = [1, 2, 3, 4, 5];

  var map = Map<int,int>.fromIterable(iterable,
      key : (element)  {
        return element;
      } // Optional Named Parameter.
      ,
      value : (element)  {
         return element * element;
      } // Optional Named Parameter.
  );
  print(map); // {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
}
Map.fromEntries(..)
factory Map.fromEntries(Iterable<MapEntry<K, V>> entries) =>  <K, V>{}..addEntries(entries);
Erstellen Sie eine Map mit den aus dem bereitgestellten MapEntry erhaltenen Mappings.
map_fromEntries_ex1.dart
void main() {
  MapEntry<String, String> entry1 = MapEntry('01000005', 'Tom');
  var entry2 = MapEntry('01000002', 'Jerry');
  var entry3 = MapEntry('01000004', 'Donald');

  // Create an Iterable via the List syntax.
  Iterable<MapEntry<String, String>> entries = [entry1, entry2, entry3];
  var phonebook = Map.fromEntries(entries);

  print(phonebook); // {01000005: Tom, 01000002: Jerry, 01000004: Donald}
}

3. Properties

Die Properties
Iterable<K> get keys;
Iterable<V> get values;
Iterable<MapEntry<K, V>> get entries;
int get length;
bool get isEmpty;
bool get isNotEmpty;

4. Methods

Die Methode
// Operators:
V? operator [](Object? key);

// Methods:
static Map<K2, V2> castFrom<K, V, K2, V2>(Map<K, V> source) => CastMap<K, V, K2, V2>(source);  
    
Map<RK, RV> cast<RK, RV>();
bool containsValue(Object? value);
bool containsKey(Object? key);

void addEntries(Iterable<MapEntry<K, V>> newEntries);
V update(K key, V update(V value), {V ifAbsent()?});
void updateAll(V update(K key, V value));
void removeWhere(bool test(K key, V value));
V putIfAbsent(K key, V ifAbsent());
void addAll(Map<K, V> other);
V? remove(Object? key);
void clear();
void forEach(void action(K key, V value));

5. addAll(Map<K, V> other)

void addAll(Map<K, V> other);
Fügen Sie dieser Map alle Schlüssel-Wert-Paare von other hinzu. Wenn der Schlüssel bereits in der Map vorhanden ist, wird sein entsprechender Wert durch den neuen Wert ersetzt.
map_addAll_ex1.dart
void main() {
  // Map<String,String>
  var options = {
    'configFile': 'config.conf',
    'outDir': './work/out',
    'inputDir': './work/in'
  };
  // Map<String,String>
  var other = {
    'outDir': './data/output',
    'inputDir': './data/input',
    'libraryDir': './libs',
    'logDir': './logs'
  };
  options.addAll(other);
  for (var entry in options.entries) {
    print('${entry.key} --> ${entry.value}');
  }
}
Output:
configFile --> config.conf
outDir --> ./data/output
inputDir --> ./data/input
libraryDir --> ./libs
logDir --> ./logs

6. addEntries(..)

void addEntries(Iterable<MapEntry<K, V>> newEntries);
Fügen Sie dieser Map alle Schlüssel-Wert-Paare aus MapEntry(s) hinzu. Wenn der Schlüssel bereits vorhanden ist, wird sein entsprechender Wert durch den neuen Wert ersetzt.
Zum Beispiel:
map_addEntries_ex1.dart
void main() {
  // Employee Number --> Salary
  // Map<String,int>
  var empSalaryMap =  {
    'E01': 800,
    'E02': 20000,
    'E03': 700
  };
  MapEntry<String,int> entry3 = MapEntry('E03', 3000);
  var entry4 = MapEntry('E04', 4000);
  var entry5 = MapEntry('E05', 5000);

  // Create an Iterable through the List syntax.
  Iterable<MapEntry<String,int>> newEntries = [entry3, entry4, entry5];
  empSalaryMap.addEntries(newEntries);
  print(empSalaryMap); // {E01: 800, E02: 20000, E03: 3000, E04: 4000, E05: 5000}
}

7. cast<RK, RV>()

Map<RK, RV> cast<RK, RV>();
Gibt eine Ansicht dieser Map<K,V> als Map<RK,RV> zurück.
Zum Beispiel:
map_cast_ex1.dart
class Person {}
class Employee extends Person {
  String name;
  Employee(this.name);
}
void main() {
  var p1 = Employee('Jennifer');
  var p2 = Employee('James');
  var p3 = Employee('John');
  // int id --> Person
  Map<int, Person> personMap = {11: p1, 21: p2, 23: p3};

  Map<int, Employee> empMap = personMap.cast();
  // or
  var empMap2 = personMap.cast<int, Employee>();

  Iterable<Employee> emps = empMap.values;
  for (var emp in emps) {
    print(emp.name);
  }
}

8. castFrom<K, V, K2, V2>(..)

static Map<K2, V2> castFrom<K, V, K2, V2>(Map<K, V> source) => CastMap<K, V, K2, V2>(source);
Eine statische Methode, die eine Ansicht einer Map<K,V> als Map<RK,RV> zurückgibt.
Zum Beispiel:
map_castFrom_ex1.dart
class Person {}
class Employee extends Person {
  String name;
  Employee(this.name);
}

void main() {
  var p1 = Employee('Jennifer');
  var p2 = Employee('James');
  var p3 = Employee('John');
  // int id --> Person
  Map<int, Person> personMap = {11: p1, 21: p2, 23: p3};

  Map<int, Employee> empMap = Map.castFrom(personMap);
  // or
  var empMap2 = Map.castFrom<int, Person, int, Employee>(personMap);

  Iterable<Employee> emps = empMap2.values;
  for (var emp in emps) {
    print(emp.name);
  }
}

9. clear()

void clear();
Entfernen Sie alle in Map enthaltenen Mapping.
map_clear_ex1.dart
void main() {
  Map<String, String> phonebook = {'01000005': 'Tom', '01000002': 'Jerry'};
  print(phonebook);
  phonebook.clear();
  print(' --- after clear() --- ');
  print(phonebook);
}
Output:
{01000005: Tom, 01000002: Jerry}
 --- after clear() ---
{}

10. containsKey(Object? key)

bool containsKey(Object? key);
Überprüft, ob ein bestimmter Schlüssel in dieser Map vorhanden ist.
Zum Beispiel:
map_containsKey_ex1.dart
void main() {
  var phonebook = <String, String>{'01000005': 'Tom', '01000002': 'Jerry'};
  var key1 = '99999999';
  var contains1 = phonebook.containsKey(key1); // false
  print('contains key ${key1}?  ${contains1}');

  var key2 = '01000005';
  var contains2 = phonebook.containsKey(key2); // true
  print('contains key ${key2}?  ${contains2}');
}
Output:
contains key 99999999?  false
contains key 01000005?  true

11. containsValue(Object? value)

bool containsValue(Object? value);
Überprüft, ob ein bestimmter Wert in dieser Map vorhanden ist.
Zum Beispiel:
map_containsValue_ex1.dart
void main() {
  Map<String, String> phonebook = {
    '01000005': 'Tom',
    '01000002': 'Jerry',
    '01000003': 'Tom'
  };
  print(phonebook.containsValue('Tom')); // true
  print(phonebook.containsValue('Donald')); // false
}

12. forEach(..)

void forEach(void action(K key, V value));
Rufen Sie die Funktion action für jeden Schlüssel und Paarwert dieser Map auf.
Zum Beispiel:
map_forEach_ex1.dart
void main() {
  // Employee Number --> Salary
  // Map<String,int>
  var empSalaryMap = {
    'E01': 1200,
    'E02': 2000,
    'E03': 1500
  };
  // A Closure
  var action = (String empNumber, int salary) {
    print('Emp Number: $empNumber, salary: $salary');
  };
  empSalaryMap.forEach(action);
}
Output:
Emp Number: E01, salary: 1200
Emp Number: E02, salary: 2000
Emp Number: E03, salary: 1500

13. putIfAbsent(..)

V putIfAbsent(K key, V ifAbsent());
Fügt dieser Map eine Mapping hinzu, wenn der angegebene Schlüssel noch nicht vorhanden ist, andernfalls wird keine Aktion ausgeführt.
map_putIfAbsent_ex1.dart
void main() {
  Map<String, int> scores = {'Bob': 36};
  for (var key in ['Bob', 'Rohan', 'Sophena']) {
    scores.putIfAbsent(key, () => key.length);
  }
  print(scores['Bob']); // 36
  print(scores['Rohan']); //  5
  print(scores['Sophena']); //  7
}

14. remove(Object? key)

V? remove(Object? key);
Entfernt die dem angegebenen Schlüssel entsprechende Zuordnung.
Zum Beispiel:
map_remove_ex1.dart
void main() {
  // Employee Number --> Salary
  // Map<String,int>
  var empSalaryMap = {
    'E01': 1200,
    'E02': 2000,
    'E03': 1500
  };
  var salary = empSalaryMap.remove('E02');
  print('Salary: $salary'); // 2000
  print(empSalaryMap); // {E01: 1200, E03: 1500}
}

15. removeWhere(..)

void removeWhere(bool test(K key, V value));
Entfernt alle Mappings, die den Test der angegebenen Funktion bestehen.
Beispiel: Eine Map<String,int> enthält die Mappings zwischen Mitarbeitercode und Gehalt. Entfernen Sie alle Mappings mit einem Gehalt von weniger als 2000.
map_removeWhere_ex1.dart
void main() {
  // Employee Number --> Salary
  // Map<String,int>
  Map<String,int> empSalaryMap = {
    'E01': 1200,
    'E02': 2000,
    'E03': 1500,
    'E04': 1700,
    'E05': 5500
  };
  // A Closure
  var test = (String empNumber, int salary) {
    return salary < 2000;
  };
  empSalaryMap.removeWhere(test);
  print(empSalaryMap); // {E02: 2000, E05: 5500}
}
Output:
{E02: 2000, E05: 5500}

16. update(..)

V update(
    K key,
    V update( V value ),
    {V ifAbsent( )?} // Optional Named Parameter
)
Aktualisiert einen neuen Wert für den bestimmten Schlüssel.
  • Existiert der bestimmte Schlüssel bereits in dieser Map, wird der neue Wert durch die bereitgestellte Funktion update berechnet.
  • Wenn der angegebene Schlüssel in dieser Map nicht vorhanden ist, wird die Funktion ifAbsent verwendet, um den Wert zu berechnen, oder null, wenn die Funktion ifAbsent nicht bereitgestellt wird.
Zum Beispiel:
map_update_ex1.dart
void main() {
  // Employee Number --> Salary
  // Map<String,int>
  var empSalaryMap =  {
    'E01': 1500,
    'E02': 2500,
    'E03': 3500
  };
  for(var key in ['E02', 'E05', 'E07']) {
      var newValue = empSalaryMap.update(key,
                                      (value)   {
                                          return value * 2;
                                      },  
                                      ifAbsent: () => 111 // Named Optional Parameter.
                                  );
  }
  print(empSalaryMap); // {E01: 1500, E02: 5000, E03: 3500, E05: 111, E07: 111}
}
Output:
{E01: 1500, E02: 5000, E03: 3500, E05: 111, E07: 111}

17. updateAll(..)

void updateAll(V update(K key, V value));
Aktualisieren Sie alle Werte dieser Map mit den neuen Werten, die von der bereitgestellten Funktion update berechnet werden.
Beispiel: Eine Map<String,int> enthält die Mappings zwischen Mitarbeitercode und Gehalt. Verwenden Sie die Methode updateAll, um das doppelte Gehalt zu aktualisieren, wenn es weniger als 1000 beträgt.
map_updateAll_ex1.dart
void main() {
  // Employee Number --> Salary
  // Map<String,int>
  var empSalaryMap = {
    'E01': 800,
    'E02': 20000,
    'E03': 700
  };
  // A Closure
  var update = (String empNumber, int salary) {
    if (salary < 1000) {
      return salary * 2;
    }
    return salary;
  };
  empSalaryMap.updateAll(update);
  print(empSalaryMap); // {E01: 1600, E02: 20000, E03: 1400}
}
Output:
{E01: 1600, E02: 20000, E03: 1400}