Bootstrap

Maps - это key-value структуры данных.

Maps - это key-value структуры данных.

Maps - это key-value структуры данных.

Неизменяемость и создание нового `Map` в Elixir

В Elixir структуры данных, такие как Map, являются неизменяемыми. Это означает, что вы не можете изменить их "на месте". Вместо этого, когда вы пытаетесь изменить Map, вы создаете новую структуру данных, а старая остаётся нетронутой. Это важное свойство, которое помогает избежать побочных эффектов в функциональном программировании.

Разбор вашего примера

Ваш пример:

Terminal:

map = %{a: 1, b: 2}
new_map = %{map | a: 3}
  • Исходный map: Вы имеете map с двумя ключами :a и :b, где :a имеет значение 1, а :b2.
  • Создание нового Map: Когда вы делаете %{map | a: 3}, вы создаете новый Map, в котором ключ :a обновляется на 3. Новый Map будет выглядеть так: %{a: 3, b: 2}.

Где старая версия `Map`?

  • Старая версия (или исходный map), где :a равно 1, всё еще существует в памяти и доступна. Вы можете ссылаться на неё с помощью переменной map, которая была определена раньше: ``elixir IO.inspect(map) # Выведет %{a: 1, b: 2} IO.inspect(new_map) # Выведет %{a: 3, b: 2} ``

Преимущества неизменяемости

  1. Безопасность: Поскольку данные неизменяемы, вы исключаете возможность случайного изменения значений в коде.
  2. Простота отладки: Легче отслеживать состояние данных в программе, так как вы всегда знаете, что изменения создают новые копии.
  3. Поддержка параллелизма: Неизменяемые структуры обеспечивают безопасный доступ из разных потоков или процессов, поскольку данные не будут изменяться "на лету".

Заключение

Неизменяемость в Elixir важна для обеспечения предсказуемости и безопасности кода. Когда вы создаете новый Map, весь предыдущий контекст остается доступным и неизменным, что делает функциональное программирование удобным для управления состоянием.


ключи строки

m = %{"a" => 42, "b" => 100}

кдючи атомы

m2 = %{:a => 42, :b =>100}

iex(1)> m = %{"a" => 42, "b" => 100}

%{"a" => 42, "b" => 100}

iex(2)> m["b"]

100

iex(3)> m["c"]

nil

iex(4)> m2 = %{:a => 42, :b =>100}

%{a: 42, b: 100}

iex(12)> %{:a => 42, :b =>100} = %{a: 42, b: 100}

%{a: 42, b: 100}

iex(5)> m[:a]

nil

iex(6)> m2[:a]

42

iex(7)> m2.a

42

iex(8)> m2.c

** (KeyError) key :c not found in: %{a: 42, b: 100}

iex(8)> Map.get(m,"a")

42

iex(9)> Map.get(m2,"a")

nil

iex(10)> Map.get(m2,"a",:default)

:default

iex(11)> Map.fetch(m2, :b)

{:ok, 100}

iex(13)> Map.fetch(m2, :c)

:error

с восклицательным знаком

iex(14)> Map.fetch!(m2, :c)

** (KeyError) key :c not found in: %{a: 42, b: 100}

(stdlib 4.2) :maps.get(:c, %{a: 42, b: 100})

iex(14)> Map.fetch!(m2, :b)

100

имутабельность данных не меняет мапу а создаёт новый мам

iex(15)> Map.put(m, :c, 500)

%{:c => 500, "a" => 42, "b" => 100}

iex(16)> m

%{"a" => 42, "b" => 100}

iex(17)> m3=Map.put(m, :c, 500)

%{:c => 500, "a" => 42, "b" => 100}

iex(18)> m

%{"a" => 42, "b" => 100}

iex(19)> m3

%{:c => 500, "a" => 42, "b" => 100}

существующем ключе меняется значение

iex(20)> m3=Map.put(m3, :c, 5050)

%{:c => 5050, "a" => 42, "b" => 100}

iex(21)> m3

%{:c => 5050, "a" => 42, "b" => 100}

изменить значение существующих ключей:

%{"a" => 42, "b" => 100}

iex(2)> %{ma: 43, b: 108}

** (KeyError) key :a not found in: %{"a" => 42, "b" => 100}

(stdlib 4.2) :maps.update(:a, 43, %{"a" => 42, "b" => 100})

(stdlib 4.2) erl_eval.erl:309: anonymous fn/2 in :erl_eval.expr/6

(stdlib 4.2) lists.erl:1350: :lists.foldl/3

iex(2)> %{m"a" 43, "b" 108}

** (SyntaxError) iex:2:11: syntax error before: "43"

2%{m"a" 43, "b" 108}
^
iex(2)> %{m"a" => 43, "b" => 108}

%{"a" => 43, "b" => 108}

iex(3)> m

%{"a" => 42, "b" => 100}

Отлично ?

Ниже — полная таблица всех функций для работы с Map в Elixir, с короткими описаниями и примерами, в том же формате, что и предыдущие шпаргалки (для String и List).

Актуально для Elixir 1.17 / OTP 27.


? Модуль `Map`

> Map — основной модуль для работы с ассоциативными коллекциями (%{ключ => значение}),

> где ключи могут быть любыми сравнимыми типами (обычно — атомы, числа или строки).


? Создание и базовые операции

ФункцияНазначениеПример
%{}Литерал map%{a: 1, b: 2}
Map.new/0Пустая картаMap.new() #=> %{}
Map.new/1Из перечисленияMap.new([{:a,1},{:b,2}]) #=> %{a: 1, b: 2}
Map.new/2Преобразование с функциейMap.new([1,2,3], fn x -> {x, x*x} end) #=> %{1=>1,2=>4,3=>9}
%{map | key => val}Обновление значения (ключ должен существовать)m=%{a:1}; %{m | a:2} #=> %{a:2}
Map.put/3Добавить/заменить паруMap.put(%{a:1}, :b, 2) #=> %{a:1,b:2}
Map.put_new/3Добавить только если ключа нетMap.put_new(%{a:1}, :a, 9) #=> %{a:1}
Map.put_new_lazy/3Вычислить значение ленивоMap.put_new_lazy(%{}, :x, fn -> 42 end)
Map.update/4Обновить значение с функциейMap.update(%{a:1}, :a, 0, &(&1+1)) #=> %{a:2}
Map.update!/3То же, но без значения по умолчаниюMap.update!(%{a:1}, :a, &(&1+1)) #=> %{a:2}
Map.replace!/3Заменить, если ключ существуетMap.replace!(%{a:1}, :a, 9) #=> %{a:9}
Map.replace/3Заменить, не создавая новый ключMap.replace(%{a:1}, :b, 2) #=> %{a:1}

? Чтение и доступ

ФункцияНазначениеПример
Map.get/2Получить значениеMap.get(%{a:1}, :a) #=> 1
Map.get/3С дефолтным значениемMap.get(%{}, :x, 0) #=> 0
Map.fetch/2Возвращает {:ok, val} или :errorMap.fetch(%{a:1}, :a) #=> {:ok,1}
Map.fetch!/2Как get, но бросает ошибкуMap.fetch!(%{a:1}, :b) #=> KeyError
Map.get_lazy/3Значение по умолчанию вычисляется функциейMap.get_lazy(%{}, :x, fn -> 99 end)
Map.pop/2Извлечь и удалить ключMap.pop(%{a:1,b:2}, :a) #=> {1, %{b:2}}
Map.pop/3С дефолтным значениемMap.pop(%{}, :x, 0) #=> {0, %{}}
Map.pop_lazy/3Дефолт вычисляется функциейMap.pop_lazy(%{}, :x, fn -> 5 end)
Map.get_and_update/3Получить и изменить через функциюMap.get_and_update(%{a:1}, :a, fn val -> {val, val+1} end)
Map.get_and_update!/3Как выше, но без дефолтаMap.get_and_update!(%{a:1}, :a, fn v -> {v, v*2} end)

? Удаление ключей

ФункцияНазначениеПример
Map.delete/2Удалить по ключуMap.delete(%{a:1,b:2}, :a) #=> %{b:2}
Map.drop/2Удалить несколько ключейMap.drop(%{a:1,b:2,c:3}, [:a,:b]) #=> %{c:3}
Map.take/2Оставить только указанные ключиMap.take(%{a:1,b:2}, [:a]) #=> %{a:1}
Map.pop/2Извлечь и удалитьMap.pop(%{x:1}, :x) #=> {1, %{}}

? Информация и проверка

ФункцияНазначениеПример
Map.has_key?/2Проверяет наличие ключаMap.has_key?(%{a:1}, :a) #=> true
Map.equal?/2Проверяет равенство двух картMap.equal?(%{a:1}, %{a:1}) #=> true
map_size/1 (Kernel)Кол-во парmap_size(%{a:1,b:2}) #=> 2

? Извлечение ключей и значений

ФункцияНазначениеПример
Map.keys/1Список ключейMap.keys(%{a: 1,b: 2}) #=> [:a,:b]
Map.values/1Список значенийMap.values(%{a: 1,b: 2}) #=> [1,2]
Map.to_list/1Преобразовать в keyword-парыMap.to_list(%{a: 1,b: 2}) #=> [a:1,b:2]
Enum.into/2Преобразовать коллекцию в mapEnum.into([{:a , 1}], %{}) #=> %{a:1}

? Объединение и слияние

ФункцияНазначениеПример
Map.merge/2Объединяет два mapMap.merge(%{a:1}, %{b:2}) #=> %{a:1,b:2}
Map.merge/3С пользовательской функциейMap.merge(%{a:1}, %{a:10}, fn _k,v1,v2 -> v1+v2 end) #=> %{a:11}
Enum.into/2Слияние коллекции в mapEnum.into([{:x,9}], %{a:1}) #=> %{a:1,x:9}

? Преобразование

ФункцияНазначениеПример
Map.from_struct/1Структура → mapMap.from_struct(%URI{path: "/foo"})
Map.to_list/1Map → список парMap.to_list(%{a:1,b:2}) #=> [a:1,b:2]
Map.new/1Список пар → mapMap.new([{:a,1},{:b,2}])

? Структуры (`struct`)

ФункцияНазначениеПример
Map.from_struct/1Преобразует структуру в mapMap.from_struct(%URI{path: "/foo"})
Map.merge/2Объединяет два map или структурыMap.merge(%URI{}, %{path: "/"})
Kernel.struct/2Создаёт структуру из mapstruct(User, %{name: "Tom"})
Kernel.struct!/2То же, но требует все ключиstruct!(User, %{name: "Tom", age: 20})

? Сопоставление с образцом

КонструкцияНазначениеПример
%{key: val} = mapДеструктуризация%{a: x} = %{a: 10, b: 20} #=> x=10
%{key => value}Динамические ключиkey=:a; %{^key => v} = %{a: 1} #=> v=1
Map.fetch!/2Проверка при pattern matchMap.fetch!(map, :x)

? Из `Enum` и `Kernel` (часто применяются к map)

ФункцияНазначениеПример
Enum.map/2Преобразовать парыEnum.map(%{a:1,b:2}, fn {k,v} -> {k,v*2} end)
Enum.each/2ИтерацияEnum.each(%{a:1}, fn {k,v} -> IO.puts("#{k}=#{v}") end)
Enum.filter/2Фильтрация по условиюEnum.filter(%{a:1,b:2}, fn {_,v} -> v>1 end)
Enum.into/2Преобразовать в mapEnum.into([{:x,1}], %{})
Map.merge/2Объединить два mapMap.merge(%{a:1}, %{b:2})

? Пример частых комбинаций

ЦельПример
Получить или задать значение по ключуm = %{x: 1}; m[:x] #=> 1; %{m | x: 2}
Объединить с дефолтамиMap.merge(%{a:1}, %{a:99,b:2}, fn _,v1,_ -> v1 end)
Удалить несколько ключейMap.drop(m, [:a,:b])
Оставить только нужныеMap.take(m, [:id,:name])
Проверить ключMap.has_key?(m, :id)
Преобразовать значенияEnum.map(m, fn {k,v} -> {k, v*2} end) | > Enum.into(%{})

⚙️ Полезные из `Kernel` (работают с map напрямую)

Функция/операторНазначениеПример
m[:key]Получение значения (или nil)%{a:1}[:a] #=> 1
%{m | key: value}Обновить существующий ключ%{a:1,b:2} | > Map.put(:c,3)
map_size/1Количество парmap_size(%{a:1,b:2}) #=> 2
is_map/1Проверка типаis_map(%{}) #=> true

Примеры использования функции `Map.put` в Elixir

Функция Map.put позволяет добавлять или обновлять значения в структуре данных типа Map. Она принимает три аргумента:

  1. Исходный Map.
  2. Ключ, под которым нужно сохранить значение.
  3. Значение, которое нужно сохранить.

После выполнения Map.put возвращается новая версия Map, содержащая обновленные данные.


Примеры использования

1. Добавление нового элемента

Terminal:

map = %{a: 1, b: 2}
updated_map = Map.put(map, :c, 3)

# Результат
# updated_map будет %{a: 1, b: 2, c: 3}

2. Обновление существующего элемента

Terminal:

map = %{a: 1, b: 2}
updated_map = Map.put(map, :b, 3)

# Результат
# updated_map будет %{a: 1, b: 3}

3. Использование с различными типами ключей и значений

Terminal:

map = %{"name" => "John", age: 30}
updated_map = Map.put(map, :email, "john@example.com")

# Результат
# updated_map будет %{"name" => "John", age: 30, email: "john@example.com"}

4. Вложенные Maps

Terminal:

map = %{user: %{name: "Alice", age: 25}}
updated_map = Map.put(map, :user, Map.put(map.user, :age, 26))

# Результат
# updated_map будет %{user: %{name: "Alice", age: 26}}

5. Использование в функциях

Вы можете использовать Map.put внутри других функций, чтобы обновлять значения по мере необходимости.

Terminal:

defmodule User do
  def update_email(user, new_email) do
	Map.put(user, :email, new_email)
  end
end

user = %{name: "Alice", email: "old_email@example.com"}
updated_user = User.update_email(user, "new_email@example.com")

# Результат
# updated_user будет %{name: "Alice", email: "new_email@example.com"}

Копирование материалов разрешается только с указанием автора Roman Sakhno и индексируемой прямой ссылкой на сайт (http://itdid.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/sahroman.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/sahroman.

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:

    Она выглядит вот так: Как настроить свой компьютер

  2. Текстовая ссылка:

    Она выглядит вот так: Как настроить свой компьютер

  3. BB-код ссылки для форумов (например, можете поставить её в подписи):

Комментарии (0):

Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.

крипто-донат, на развитие сайта itdid.ru:

В новом окне с терминалом itdid.ru, введите любую сумму: