我想对一系列价值组合进行一些分析。
我有以下函数,但由于某种原因,在完成了理解之后并且在函数体的末尾,变量analytics
仍然是一个空列表,而它不在每次迭代的理解之内
有什么想法吗?
def handle_cast({:start}, state) do
intervals = [7, 30, 90]
groupings = ["day_of_week", "time_of_day"]
aggregators = [
%{
domain: "support",
metric: "new_conversations",
func: &App.get_new_conversations/2
},
%{
domain: "support",
metric: "closed_conversations",
func: &App.get_closed_conversations/2
},
%{
domain: "support",
metric: "median_response_time",
func: &App.get_median_response_time/2
},
]
Repo.transaction(fn ->
Repo.delete_all(Analytic)
analytics = []
for interval <- intervals do
for grouping <- groupings do
for %{domain: domain, metric: metric, func: func} <- aggregators do
analytic =
func.(grouping, interval)
|> Enum.map(fn %{"app_id" => app_id, "data" => data} = result ->
%Analytic{app_id: app_id, domain: domain, metric: metric, grouping: grouping, interval_in_days: interval, data: data}
end)
analytics = [analytic|analytics]
end
end
end
end)
{:noreply, state}
end
答案 0 :(得分:3)
Elixir中的变量是不可变的但可重新绑定。这意味着行analytics = [analytic|analytics]
正在创建一个新列表并将其绑定到该块范围的名为analytics
的变量。当块结束时,更改不会在for
的下一次迭代中保留。例如:
iex(1)> x = 1
1
iex(2)> for i <- 1..3 do
...(2)> IO.puts(x); x = x + i; IO.puts(x)
...(2)> end
1
2
1
3
1
4
对于您编写的代码,您可以使用for
返回其中最后一个表达式的值列表的事实,并将最外层for
的返回值存储到analytics
,但是存在轻微问题:您最终会遇到嵌套列表:
iex(1)> for i <- 1..2 do
...(1)> for j <- 1..2 do
...(1)> for k <- 1..2 do
...(1)> {i, j, k}
...(1)> end
...(1)> end
...(1)> end
[[[{1, 1, 1}, {1, 1, 2}], [{1, 2, 1}, {1, 2, 2}]],
[[{2, 1, 1}, {2, 1, 2}], [{2, 2, 1}, {2, 2, 2}]]]
但是,这是一个简单的解决方案! for
在一次调用中接受多个<-
子句,并自动返回一个平面列表:
iex(1)> for i <- 1..2, j <- 1..2, k <- 1..2 do
...(1)> {i, j, k}
...(1)> end
[{1, 1, 1}, {1, 1, 2}, {1, 2, 1}, {1, 2, 2}, {2, 1, 1}, {2, 1, 2}, {2, 2, 1},
{2, 2, 2}]
使用此方法,您的代码变为:
analytics =
for interval <- intervals,
grouping <- groupings,
%{domain: domain, metric: metric, func: func} <- aggregators do
func.(grouping, interval)
|> Enum.map(fn %{"app_id" => app_id, "data" => data} = result ->
%Analytic{app_id: app_id, domain: domain, metric: metric, grouping: grouping, interval_in_days: interval, data: data}
end)
end
end
end
这应该会为您提供与原始代码相同的输出。