Эликсир сделать ссылку на себя - PullRequest
0 голосов
/ 03 июля 2019

У меня есть эта карта

%{
  total: 38,
  value: 22
}

И хотел бы добавить ключ :ratio. Есть ли способ написать сразу:

%{
  total: 38,
  value: 22,
  ratio: __SELF__.value / __SELF__.total
}

или мне нужно создать другую карту для достижения этой цели?

Спасибо

Ответы [ 2 ]

2 голосов
/ 03 июля 2019

Все данные неизменны, поэтому вам всегда нужно создавать новую карту.

Простой способ, предполагая, что ваша карта называется map:

iex> Map.put(map, :ratio, map.value / map.total)
%{ratio: 0.5789473684210527, total: 38, value: 22}

Если вы имеете в виду, чтоВы хотите создать карту до того, как она уже существует, тогда было бы лучше поместить total и value в переменные и использовать их для построения карты:

defmodule Example do
  def make_map(total, value) do
    %{total: total, value: value, ratio: value / total}
  end
end

iex(1)> Example.make_map(38, 22)
%{ratio: 0.5789473684210527, total: 38, value: 22}
0 голосов
/ 03 июля 2019

Я действительно хотел избежать назначения временной карты переменной.

Что ж, поскольку данные в определенном месте памяти неизменны, elixir может безопасно использовать указатели на эти места памяти.внутри новые коллекции.Поэтому создание временной переменной с промежуточными результатами не удваивает объем используемой памяти.Например, если вы начинаете с карты, содержащей 1 миллион записей, и создаете новую карту с одной дополнительной записью, вы не используете общую память:

  old_map       new_map
    |              |
    V              V
1 million + ( 1 million + 1) 

Скорее, вы используете только дополнительную память:

   new_entry
      |
      V
      1 + pointer_to_old_map

... плюс немного больше для учета новой карты.Вот так:

             old_map
               ^
               |
 new_map = %{  +, a: 10}

Есть ли способ написать сразу:

%{
  total: 38,
  value: 22,
  ratio: __SELF__.value / __SELF__.total
}

Да:

%{
  total: 38,
  value: 22,
  ratio: 22/38
}

Теперь, если выесть список карт, к которым вы хотите добавить коэффициент:

data = [
  %{total: 38, value: 22},
  %{total: 40, value: 22},
  %{total: 44, value: 22}
]

for %{total: t, value: v}=map <- data do
  Map.put(map, :ratio, v/t)
end

вывод:

[
  %{ratio: 0.5789473684210527, total: 38, value: 22},
  %{ratio: 0.55, total: 40, value: 22},
  %{ratio: 0.5, total: 44, value: 22}
]

После каждой итерации for comprehension места памяти t и v немедленно подвергаются сборке мусора, и на новой карте используется указатель на область памяти map.

...