betacode

Руководство 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>

На языке Dart, класс Map<K,V> представляет структуру данных, состоящую из сопоставлений между ключами и значениями. Ключи нельзя дублировать, и каждый ключ будет соответствовать определенному значению.
Одним из типичных примеров, которые можно привести здесь, является телефонная книга. Номер телефона является ключом, а имя владельца номера телефона является значением.
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
Иерархия классов группы Map:
  • LinkedHashMap

2. Constructors

Конструкторы::
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();
Создает пустую LinkedHashMap.
Map.from(Map other)
factory Map.from(Map other) = LinkedHashMap<K, V>.from;
Создает LinkedHashMap со всеми сопоставлениями, импортированными из other.
Этот конструктор не проверяет тип данных other, поэтому во время выполнения приложения может возникнуть ошибка. Вы должны предпочесть использовать конструктор Map.of, если это возможно.
Например:
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;
Создает LinkedHashMap со всеми сопоставлениями, импортированными из other.
Map.identity()
factory Map.identity() = LinkedHashMap<K, V>.identity;
Возвращает "Identity Map", которая представляет собой Map, использующую hashcode и функцию identical для сравнения двух ключей. (Смотрите дополнительные пояснения в статье о LinkedHashMap).
  • Dart LinkedHashMap
Map.unmodifiable(..)
external factory Map.unmodifiable(Map<dynamic, dynamic> other);
Создает неизменяемый (unmodifiable) объект Map со всеми сопоставлениями, импортированными из other.
Map.fromIterable(..)
factory Map.fromIterable(Iterable iterable,
             {K key(dynamic element)?, V value(dynamic element)?}) = LinkedHashMap<K, V>.fromIterable;
Создает объект Map с ключами и значениями, вычисляемыми из элементов указанной Iterable.
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);
Создайте Map с отображениями, полученными из предоставленной MapEntry.
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

Свойства:
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

Методы:
// 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);
Добавьте все пары ключей и значений of other на эту Map. Если ключ уже существует на Map, его соответствующее значение будет заменено новым значением.
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);
Добавьте все пары ключей и значений из MapEntry на эту Map. Если ключ уже существует, его соответствующее значение будет заменено новым значением.
Например:
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>();
Возвращает представление этой Map<K,V> как Map<RK,RV>.
Например:
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);
Статический метод, который возвращает представление Map<K,V> в виде Map<RK,RV>.
Например:
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();
Удалите все сопоставления, содержащиеся в Map.
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);
Проверяет, существует ли указанный ключ на этой Map.
Например:
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);
Проверяет, существует ли указанное значение на этой Map.
Например:
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));
Вызовите функцию action для каждого ключа и значения пары этой Map.
Например:
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());
Добавляет сопоставление к этой Map, если указанный ключ еще не существует, в противном случае никаких действий не предпринимается.
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);
Удаляет сопоставление, соответствующее указанному ключу.
Например:
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));
Удаляет все сопоставления, которые проходят проверку указанной функцией.
Например: Map<String,int> содержит сопоставления между кодом сотрудника и зарплатой. Удалите все сопоставления с зарплатой менее 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
)
Обновляет новое значение для указанного ключа.
  • Если указанный ключ уже существует на этой Map, новое значение будет рассчитано с помощью предоставленной функции update.
  • Если указанный ключ не существует в этой Map, для вычисления значения будет использоваться функция ifAbsent, или значение null, если функция ifAbsent не предусмотрена.
Например:
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));
Обновите все значения этой Map с помощью новых значений, рассчитанных с помощью предоставленной функции update.
Например: Map<String,int> содержит сопоставления между кодом сотрудника и зарплатой. Используйте метод updateAll, чтобы обновить двойную зарплату, если она меньше 1000.
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}