长生不老药在地图上做自我参考

时间:2019-07-03 13:45:46

标签: dictionary elixir

我有这张地图

%{
  total: 38,
  value: 22
}

,并想添加密钥:ratio。有没有一种立即写的方法:

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

还是我需要创建另一个地图来实现这一目标?

谢谢

2 个答案:

答案 0 :(得分:2)

所有数据都是不可变的,因此您始终必须制作一张新地图。

一种简单的方法,假设您的地图称为map

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

如果您想在地图已经存在之前就创建它,那么最好将totalvalue放入变量中,并使用它们来构建地图:

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}

答案 1 :(得分:-2)

  

我真的很想避免将临时映射分配给变量。

好吧,因为特定存储位置的数据是不可变的,所以elixir可以安全地使用指向新集合内这些存储位置的指针。因此,创建具有中间结果的临时变量不会使使用的内存量增加一倍。例如,如果您从一个包含一百万个条目的地图开始,然后创建一个包含一个附加条目的新地图,则您不会使用以下总内存:

  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的每次迭代之后,tv的存储位置将立即进行垃圾回收,并使用指向map的存储位置的指针在新地图中。