Как добавить коллекцию в map dart
Класс Map или словарь представляет коллекцию элементов, где каждый элемент имеет ключ и значение. Ключ и значение элемента могут представлять различные типы. Причем ключи представляют уникальные значения — не может быть два и более элементов с одинаковыми ключами. Такой объект напоминает словарь, где каждому слову сопоставляется его перевод или некоторое описание. Поэтому такие объекты часто называются словарями.
Для создания объекта Map могут использоваться фигурные скобки <>. Например, создание пустого словаря:
Map map = <>;
Класс Map типизируется двумя типами. Первый тип представляет тип ключей, а второй — тип значений. То есть в примере выше ключи представляют значения типа int , а значения — тип String .
Альтернативное определение пустого словаря:
var map = <>;
Также можно создать пустой словарь следующим образом:
var map = <>;
В этом случае создается словарь типа Map .
Четвертый способ создания пустого словаря представляет использование конструктора Map:
var map = Map();
Инициализация словаря
Можно сразу инициализировать объект Map значениями. Для этого в фигурных скобках через запятую определяются элементв в формате ключ : значение :
var map = < 1: "Tom", 2: "Bob", 3: "Sam" >;
В данном случае объект map имеют тип Map — в качестве типа ключей используется тип int, а в качестве типа значений — тип String. А в самом словаре есть три ключа — 1, 2, 3, с которыми сопоставляются три значения — строки «Tom», «Bob», «Sam».
Функция print позволяет удобным образом вывести содержимое словаря на консоль:
void main ()< var map = < 1: "Tom", 2: "Bob", 3: "Sam" >; print(map); // >
Стоит отметить, что все ключи должны быть уникальными. Если вдруг мы определим в словаре (или добавим в словарь) элемент с уже имеющимся ключом, то он просто затрет ранее существовавшее значение:
void main ()< var map = < 1: "Tom", 2: "Bob", 3: "Sam", 1: "Alice" >; print(map); // >
Обращение к элементам
Используя ключи, мы можем получить или изменить значения элементов:
void main ()< var map = < 1: "Tom", 2: "Bob", 3: "Sam" >; var second = map[2]; // получим значение элемента с ключом 2 print(second); // Bob map[1] = "Tomas"; // изменим значение элемента с ключом 1 print(map); // >
Для обращения к элементу после названия словаря в квадратных скобках указываем ключ элемента. Например, получение элемента с ключом 2:
var second = map[2];
Изменение значения элемента с ключом 1:
map[1] = "Tomas";
Свойства и методы Map
- entries : возвращает объект Iterable> , который представляет все элементы Map. Каждый отдельный элемент словаря представляет объект MapEntry
- keys : возвращает объект Iterable , который представляет все ключи Map
- values : возвращает объект Iterable , который представляет все значения Map
- length : возвращает количество элементов в Map
- isEmpty : возвращает true, если Map пуст
- isNotEmpty : возвращает true, если Map имеет элементы
void main ()< var map = < 1: "Tom", 2: "Bob", 3: "Sam" >; print("Length: $"); // Length: 3 print("Empty: $"); // Empty: false print(map.entries); // (MapEntry(1: Tom), MapEntry(2: Bob), MapEntry(3: Sam)) print(map.keys); // (1, 2, 3) print(map.values); // (Tom, Bob, Sam) >
Основные методы Map
- addAll(Map other) : добавляет в Map другой объект Map
- addEntries(Iterable
newEntries) : добавляет в Map коллекцию Iterable - clear() : удаляет все элементы из Map
- containsKey(Object key) : возвращает true, если Map содержит ключ key
- containsValue(Object value) : возвращает true, если Map содержит значение value
- forEach() : перебирает все элементы и для каждого из них вызывает определенную функцию
- V putIfAbsent(K key, V ifAbsent()) : если ключ key есть в Map, то возвращает значение по этому ключу. Если ключ отсутствует, то добавляет в Map значение, которое возвращается функцией isAbsent.
- remove(Object key) : удаляет из Map элемент с ключом key
Перебор Map
Для перебора объекта Map можно применять цикл for-in . Мы можем использовать свойства entries, keys, values и перебрать соответственно элементы, ключи и значения.
Стоит отметить, что каждый элемент в Map фактически представляет объект MapEntry , где K — тип ключей, а V — тип значений. У этого типа есть два свойства: key (ключ элемента) и value (хранит значение элемента). Используя эти свойства, мы можем получить содержимое элементов в Map. Например, переберем все элементы и отдельно все ключи и значения Map:
void main ()< var map = < 1: "Tom", 2: "Bob", 3: "Sam" >; for(final element in map.entries) < print(element.key); // получаем ключ элемента print(element.value); // получаем значение элемента >>
Подобным образом перебирем по отдельности ключи и значения:
void main ()< var map = < 1: "Tom", 2: "Bob", 3: "Sam" >; // перебираем ключи for(final key in map.keys) < print(key); >// перебираем значения for(final value in map.values) < print(value); >>
В качестве альтернативы можно применять метод forEach() . Он принимает функцию, в которую передается ключ и значение каждого элемента словаря:
void main ()< var map = < 1: "Tom", 2: "Bob", 3: "Sam" >; map.forEach((key, value) => print("$key - $value")); >
В данном случае в метод forEach передаем анонимную функцию, которая принимает два параметра — ключ и значение элемента и выводит их на консоль. Консольный вывод:
1 - Tom 2 - Bob 3 - Sam
Добавление элементов
Для добавления нового элемента достаточно установить элемент по ранее не существовавшему ключу:
void main ()< var map = < 1: "Tom", 2: "Bob", 3: "Sam" >; map[4] = "Alice"; // добавляем элемент с ключом 4 print(map); // >
В данном случае элемента с ключом 4 изначально нет в map. Поэтому установка значения по этому ключу приведет к добавлению нового элемента.
Метод addAll() применяется для добавления элементов из другого словаря, который передается в качестве параметра:
void main ()< var women = ; var map = < 1: "Tom", 2: "Bob", 3: "Sam" >; map.addAll(women); // добавляем словарь women print(map); // >
Удаление
Для удаления применяется метод remove() , в который передается ключ удаляемого элемента:
void main ()< var map =< 1: "Tom", 2: "Bob", 3: "Sam" >; map.remove(2); // удаляем элемент с ключом 2 print(map); // >
Проверка наличия элемента
С помощью методов containsKey() и containsValue() можно соответственно проверить наличие определенного ключа и значения в Map:
void main ()< var map =< 1: "Tom", 2: "Bob", 3: "Sam" >; print(map.containsKey(2)); // true print(map.containsKey(4)); // false print(map.containsValue("Sam")); // true print(map.containsValue("Tim")); // false >
как конвертировать коллекцию Set в коллекцию Map
Важно понимать что элементы Set’а могут быть как неупорядоченными, так и упорядоченными. Также во втором примере показал как будет более правильнее чем у вас есть сейчас.
void main() < Setara1 = ; // 1 Map ara2 = < for (int i = 0; i < ara1.length; i++) i: ara1.elementAt(i) >; ara2.forEach((k, v) < print('$k : $v'); >); print(''); // 2 List ara1Temp = ara1.toList(); Map ara3 = < for (int i = 0; i < ara1Temp.length; i++) i: ara1Temp[i] >; ara3.forEach((k, v) < print('$k : $v'); >); >
Отслеживать
ответ дан 10 окт 2021 в 7:52
5,487 1 1 золотой знак 12 12 серебряных знаков 31 31 бронзовый знак
Уважаемый MiT, огромное Вам спасибо. Мне не совсем ясно, что значит упор. и не упор. Если сортировки здесь нет, как можно упор. или не упор. коллецию? Или упор. это не есть сортировка? И по моему вариант ara1.toList().asMap(); более элегантен, не так ли?
10 окт 2021 в 8:21
@Sergey по поводу упор. и не упор.. asMap вам даёт ListMapView что не совсем является Map .
10 окт 2021 в 9:47
Уважаемый MiT, теперь ясно, спасибо.
10 окт 2021 в 9:52
Уважаемый MiT. Теперь другая неясность. Мой вариант выдает ListMapView
10 окт 2021 в 10:09
@Sergey про упор. и не упор. я больше говорил в контексте Set , так как по нему мы предполагаем что будем проходится циклом и создавать Map . Но если вас это тоже интересует the LinkedHashMap iterates in key insertion order , в документации всегда об этом пишут. А на счёт ListMapView понятия не имею.
Dart: Быстрые неизменяемые коллекции
Привет! Представляю вашему вниманию перевод статьи про возможности пакета FIC(Fast Immutable Collections, Быстрые неизменяемые коллекции). FIC — конкурент для таких пакетов как built_collection и kt_dart, но он намного быстрее и проще в использовании.

Массивы, к которым вы, возможно, привыкли в других языках, в Dart называются списками (List), и они изменяемые по умолчанию — вы можете добавлять в них новые элементы, удалять и т.д.
var list = [1, 2]; list.add(3); // list: [1, 2, 3].
Существует способ создать неизменяемый список с помощью List.unmodifiable , список, по прежнему, будет иметь метод add , который выдаст ошибку во время исполнения, при попытке данный метод вызвать:
var list = List.unmodifiable([1, 2]); list.add(3); // Ошибка во время выполнения программы.
Однако можно делать изменения в копии такого списка:
var list = List.unmodifiable([1, 2]); // Этот список нельзя изменять. var newList = list.toList()..add(3); print(newList); // [1, 2, 3].
Есть способ лучше
Как вы поняли, обычный List можно использовать как неизменяемый, но при этом приходится писать шаблонный код, его становится трудно читать. Существует другой, более хороший способ: использование IList вместо List. IList неизменяемый — неизменяемый список, с простым API для использования.
Чтобы создать IList вы можете просто использовать extension-метод lock над обычным List :
IList iList = [1, 2].lock;
Изменить содержимое IList не получится. Метод add будет возвращать новый IList с добавленным элементом:
var myList = [1, 2].lock; // Его изменить не получится. var newList = myList.add(3)); print(myList); // [1, 2]. print(newList); // [1, 2, 3].
FIC
Пакет FIC (Fast Immutable Collections, Быстрые неизменяемые коллекции) предоставляет неизменяемые списки. FIC — конкурент для таких пакетов как built_collection и kt_dart, но он намного быстрее и проще в использовании.
По ссылке Вы можете посмотреть сравнения по скорости с альтернативными пакетами. Иногда FIC даже быстрее, чем родные коллекции в Dart:

Использование
Неизменяемые коллекции имеют имена IList , ISet и IMap . Чтобы создать неизменяемую коллекцию, Вы просто можете «заблокировать» изменяемую:
IList iList = [1, 2].lock; ISet iSet = .lock; IMap iMap = .lock;
Любой Iterable также может быть заблокирован в неизменяемый список(List) или набор(Set) с помощью toIList() и toISet() соответственно, или используя конструкторы:
IList iList = myIterable.toIList(); ISet iSet = myIterable.toISet(); // С помощью конструкторов: IList iList = IList(myIterable); ISet iSet = ISet(myIterable);
Также можно «разблокировать» неизменяемые коллекции и получить изменяемые:
List list = iList.unlock; Set set = iSet.unlock; Map map = iMap.unlock; // Работает и это: List list = iList.toList(); Set set = iSet.toSet(); // Работает и это: List list = List.of(iList); Set set = Set.of(iSet);
Но помните, что те методы, которые изменяют содержимое неизменяемых коллекций возвращают коллекции с новым содержанием. К примеру:
var iList1 = [1, 2].lock; var iList2 = iList1.add(3); // [1, 2, 3]. var iList3 = iList2.remove(2); // [1, 3]. print(iList1); // Все еще [1, 2].
Благодаря этому методы можно выстраивать в цепочку:
var iList = [1, 2, 3].lock.add(4).remove(2); // [1, 3, 4].
Равенство
По умолчанию, FIC равны, если их содержимое одинаковое и находится в одном порядке:
var iList1 = [1, 2].lock; var iList2 = [1, 2].lock; print(identical(iList1, iList2)); // false. print(iList1 == iList2); // true.
Это является полной противоположностью для обычных списков(List), которые сравниваются по идентичности:
var list1 = [1, 2]; var list2 = [1, 2]; var list3 = list1; // Обычные списки(List) сравниваются по идентичности: print(identical(list1, list2)); // false. print(identical(list1, list3)); // true. print(list1 == list2); // false. // В то время как ILists сравниваются по содержимому: print(list1.lock == list2.lock); // true.
Однако, IList является настраиваемым. Вы можете создать IList , который будет сравниваться по идентичности:
// Эти ILists сравниваются по содержимому: var iList1 = [1, 2].lock; var iList2 = [1, 2].lock; print(iList1 == iList2); // true. // Теперь эти же ILists сравниваются по идентичности: var iList3 = [1, 2].lock.withIdentityEquals; var iList4 = [1, 2].lock.withIdentityEquals; print(iList3 == iList4); // false.
Сортировка
Порядок объектов в ISet и IMap может быть и тем, который Вы изначально ввели, а может быть и отсортирован в зависимости от конфигурации:
var iSet = .lock; print(iSet.join(", ")); // [2, 4, 1, 9, 3]. var iSet = .lock.withConfig(ConfigSet(sort: true)); print(iSet.join(", ")); // [1, 2, 3, 4, 9].
IMapOfSets
При блокировке Map , Вы получаете IMap .
Однако заблокированная Map> становится IMapOfSets :
// Map в IMap. IMap map = .lock; // Map в IMapOfSets. IMapOfSets map = , 'b': >.lock;
«Map of sets» — это вид мультисловаря(multimap). IMapOfSets позволяет добавлять и удалять объекты, не думая о наборах(sets), которые содержатся внутри.
К примеру:
IMapOfSets map = , 'b': >.lock; print(map.add('a', 3)); // , 'b': >.
По этой ссылке можно найти пример класса, называющийся StudentsPerCourse , который распределяет студентов по курсам. Каждый студент может быть записан в один или несколько курсов. Такую модель можно получить с помощью словаря(map), в котором ключами будут курсы, а значениями — наборы из студентов.
ListSet
Несмотря на свое название, FIC предлагает и изменяемые типы. К примеру, ListSet сразу же:
- Изменяемый, упорядоченный набор(Set) фиксированного размера.
- Изменяемый список(List) фиксированного размера, в котором значения не повторяются:
ListSet listSet = ListSet.of([1, 2, 3]); expect(listSet[2], 3); expect(listSet.contains(2), isTrue); List list = listSet; Set set = listSet; expect(list[2], 3); expect(set.contains(2), isTrue);
Если рассматривать ListSet как Set и сравнивать с LinkedHashSet , то ListSet также является упорядоченным и имеет схожую производительность. Но ListSet занимает меньше места в памяти и может быть отсортирован, так же как и List . Также, у Вас есть доступ к его элемента по индексу за константное время.
Минусом, конечно же, является, что ListSet имеет фиксированный размер, а LinkedHashSet — нет. ListSet эффективен и как List , и как Set . Поэтому, к примеру, у него есть эффективный sort метод, в то время как LinkedHashSet требует конвертации в List , сортировки, а затем обратного преобразования в Set .
Расширения, хелперы и компараторы
FIC также предоставляет:
Iterable хелперы и расширения:
- combineIterables — высокоуровневая функция, которая объединяет два Iterable в один.
- Iterable.isNullOrEmpty , Iterable.isNotNullOrEmpty и Iterable.isEmptyButNotNull .
- Iterable.deepEquals сравнивает два объекта по порядку с помощью оператора == .
- Iterable.deepEqualsByIdentity сравнивает все объекты по порядку с помощью identical .
- Iterable.findDuplicates ищет повторяющиеся значения и возвращает Set с дубликатами.
- Iterable.removeNulls убирает все объекты, равные null , из Iterable .
- Iterable.removeDuplicates убирает все повторяющиеся объекты. Дополнительно, можно использоваться by функцию для сравнения объектов. Если добавить аргумент removeNulls равное true , то уберутся и null-объекты.
- Iterable.sortedLike возвращается список, отсортированный в соответствии с Iterable сортировки. Объекты, которых нет в сортировочном Iterable , встанут в конец.
Расширения над List :
- List.sortOrdered похож на метод sort , но использует сортировку слиянием(merge sort). В противовес sort , orderedSort стабильный, что означает, что различные объекты, которые сравниваются как равные, остаются в начальном порядке.
- List.sortLike сортирует список в соответствии с ordering Iterable . Объекты, которых нет в ordering, встанут в конец в определенном порядке.
- List.moveToTheFront перемещает первое вхождение элемента в начало списка.
- List.moveToTheEnd перемещает первое вхождение элемента в конец списка.
- List.whereMoveToTheFront перемещает все элементы, которые удовлетворяют предоставленным требованиям, в начало списка.
- List.whereMoveToTheEnd перемещает все элементы, которые удовлетворяют предоставленным требованиям, в конец списка.
- List.toggle Если элемента нет в списке, добавляет его и возвращает true . Если уже есть, то удаляет первый необходимый и возвращает false .
- List.compareAsSets возвращает true если в списке есть требуемые элементы (в любом порядке). Не берутся во внимание повторяющиеся элементы.
- List.mapIndexed преобразует каждый элемент списка. Функция принимает изначальный элемент и его индекс.
- List.splitList убирает элементы из списка, которые удовлетворяют условию.
- List.divideList возвращает несколько списков, разделенных по выбранным элементам.
- List.addBetween возвращает новый список, добавив разделение между изначальными элементами.
- List.concat возвращает эффективное слияние до 5 списков.
- List.splitByLength делит список на один или несколько списков с максимальным количеством элементов length .
- List.update возвращает список, в котором новые элементы добавляются или обновляются в зависимости от порядкового номера.
- List.distinct удаляет повторяющиеся объекты, оставляя только уникальные.
- List.reversedView возвращает список объектов в обратном порядке.
Расширения над Set :
- Set.toggle Если объекта нет в Set , то он добавляется и возвращается true . Иначе, если объект уже есть в Set , то он удаляется и возвращается false .
Расширения над Iterator :
- toIterable , toList , toSet , toIList , и toISet преобразуют Iterator в Iterable , List , Set , IList , и ISet , соответственно.
Расширения над Boolean:
- compareTo делает true > false .
Компараторы
- compareObject
- compareObjectTo
- sortBy
- sortLike
- if0
Другие Flutter пакеты от автора:
- async_redux (на Medium: Асинхронный Redux: Нешаблонная версия Flutter Reduxhttps://medium.com/flutter-community/https-medium-com-marcglasberg-async-redux-33ac5e27d5f6)
- i18n_extension (на Medium: Потрясающе легкие переводы и интернационализация для Flutter приложенийhttps://medium.com/flutter-community/i18n-extension-flutter-b966f4c65df9)
- provider_for_redux
- image_pixels
- network_to_file_image
- matrix4_transform
- back_button_interceptor
- indexed_list_view
- animated_size_and_fade
- align_positioned
- assorted_layout_widgets
Что такое Map в Dart
Map — это набор пар ключ-значение. Это означает, что каждый элемент на Map состоит из двух частей: ключа и значения. Ключ используется для идентификации элемента, в то время как значение — это данные, связанные с этим элементом. При работе с картами вы можете добавлять, удалять элементы и получать доступ к ним на основе их ключей.
Создание Map
Чтобы создать Map в Dart, вы можете использовать встроенный конструктор Map или синтаксис map literal. Вот пример:
// Использование Map конструктора var myMap = Map(); // Использование literal syntax var myMap = ;
В первом примере мы создаем пустую карту с помощью конструктора Map. Во втором примере мы используем синтаксис map literal для создания карты с двумя парами ключ-значение: ‘key1’: ‘value1’ и ‘key2’: ‘value2’.
Добавление и удаление элементов в Map
Чтобы добавить элемент на карту, вы можете использовать оператор []. Чтобы удалить элемент с карты, вы можете использовать метод remove(). Вот пример:
var myMap = ; myMap['key3'] = 'value3'; // Добавляем ключ-значение в Map myMap.remove('key2'); // Удаляем ключ-значение в Map
В этом примере мы добавляем новую пару ключ-значение к карте с помощью оператора [] и удаляем пару ключ-значение с ключом ‘key2’ с помощью метода remove().
Доступ к элементам в Map
Чтобы получить доступ к элементу на карте, вы можете использовать оператор [] с ключом. Вот пример:
var myMap = ; print(myMap['key1']); // Получим: value1
В этом примере мы используем оператор [] для доступа к значению, связанному с ключом ‘key1’ на карте. Результатом выполнения инструкции print будет ‘value1’.
Перебор по Map
Чтобы выполнить итерацию по карте в Dart, вы можете использовать метод forEach(). Вот пример:
var myMap = ; myMap.forEach((key, value) < print('$key: $value'); >);
В этом примере мы используем метод forEach() для перебора пар ключ-значение в карте. Оператор print внутри метода forEach() выведет:
key1: value1 key2: value2
Преобразование Map в List
Иногда вам может понадобиться преобразовать Map в List в Dart. Вы можете сделать это, используя свойство entries, которое возвращает итерацию объектов MapEntry. Каждый объект MapEntry содержит пару ключ-значение из карты. Вот пример:
var myMap = ; var myList = myMap.entries.toList(); print(myList);
В этом примере мы используем свойство entries, чтобы получить итерацию объектов MapEntry, а затем с помощью метода ToList() преобразуем итерацию в список. Результатом выполнения инструкции print будет:
Фильтрация Map
Вы можете отфильтровать Map в Dart, используя метод where(), который возвращает новую карту, содержащую только пары ключ-значение, удовлетворяющие заданному условию. Вот пример:
var myMap = ; var filteredMap = myMap.where((key, value) => value % 2 == 0); print(filteredMap);
В этом примере мы используем метод where() для создания новой карты, содержащей только пары ключ-значение, где значение четное. Результатом выполнения инструкции печати будет:
Объединение Map
В Dart вы можете объединять Map с помощью оператора распространения …. Оператор spread позволяет вам развернуть содержимое карты или выполнить итерацию на другой карте.
Вот пример объединения двух карт:
Map map1 = ; Map map2 = ; Map mergedMap = ; print(mergedMap); // Output:
В приведенном выше примере мы сначала определяем две карты map1 и map2. Затем мы создаем новую карту mergedMap, используя оператор spread, чтобы развернуть содержимое map1 и map2 в новую карту.
Обратите внимание, что если есть ключи, которые существуют на обеих картах, будет использоваться значение ключа на последней карте. Например:
Map map1 = ; Map map2 = ; Map mergedMap = ; print(mergedMap); // Output:
В этом примере значение ключа ‘b’ в map2 перезаписывает значение того же ключа в map1.
Когда используют Map
Map полезен в ситуациях, когда вам необходимо сохранить набор пар ключ-значение, таких как словарь или файл конфигурации. Они также могут использоваться для хранения связанных данных структурированным образом, где ключи выступают в качестве меток для значений.
Заключение
Map — полезная структура данных для хранения пар ключ-значение. Он предлагает несколько методов добавления, удаления элементов и доступа к ним на основе их ключей. Карты отличаются от списков и наборов тем, что они хранят пары ключ-значение и неупорядочены. При работе с картами важно учитывать эти различия, чтобы убедиться, что вы используете правильную структуру данных для своих нужд.