使用Collector的Elixir推导未收集数据:Map为何未被填充?
问题原因与解决方法
你的问题核心是没搞清楚Elixir的不可变特性,以及for推导中into:参数的工作逻辑,具体拆解如下:
Map确实支持
into:参数,但不会修改原变量
Map实现了Collector协议,所以into:可以传入Map,但Elixir是纯不可变语言——你传入into: m时,推导会基于初始的空Map创建新的Map,而完全不会修改原来绑定的m变量。你最后输出的m还是最开始的空Map,自然长度为0。循环体内访问的是初始的空Map
循环里的m是代码最开始绑定的那个空Map,每次迭代都不会变,所以三次输出都是0。必须接收
for推导的返回值for推导的返回值才是收集完成后的新Map,你没有接收这个值,所以看不到预期的结果。
修正后的代码
lt = [{"ab", "cd", "ef"}, {"x", "y", "z"}] initial_m = %{} # 接收推导返回的新Map new_m = for c <- lt, into: initial_m do {elem(c, 1), elem(c, 0)} end IO.puts(length(Map.keys(new_m))) # 输出2 IO.inspect(new_m) # 输出 %{"cd" => "ab", "y" => "x"}
如果需要在迭代过程中跟踪当前收集的进度,因为不可变特性没法直接访问构建中的集合,可以用索引或者Enum.reduce实现:
lt = [{"ab", "cd", "ef"}, {"x", "y", "z"}] {final_m, _} = Enum.reduce(lt, {%{}, 0}, fn c, {acc, count} -> IO.puts(count) # 依次输出0、1 new_acc = Map.put(acc, elem(c, 1), elem(c, 0)) {new_acc, count + 1} end) IO.puts(length(Map.keys(final_m))) # 输出2 IO.inspect(final_m)
内容的提问来源于stack exchange,提问作者user1934428
相关产品推荐
相关产品推荐

