递归似乎随机复制了一些值——Elixir第14天代码2020的出现

递归似乎随机复制了一些值——Elixir第14天代码2020的出现,elixir,Elixir,我已经缩小了错误范围(至少我认为是这样),但仍然不知道为什么会发生这种情况。对于数据集: mask = 1XX010X01110X110100000X11101X10X0X11 mem[3513] = 1787222 mem[11652] = 13761 mem[25508] = 235920 mem[49386] = 7440645 mem[51287] = 197564380 mem[9697] = 1812 mem[62638] = 5207143 在应用掩码后,我得到一个由第四个内存项

我已经缩小了错误范围(至少我认为是这样),但仍然不知道为什么会发生这种情况。对于数据集:

mask = 1XX010X01110X110100000X11101X10X0X11
mem[3513] = 1787222
mem[11652] = 13761
mem[25508] = 235920
mem[49386] = 7440645
mem[51287] = 197564380
mem[9697] = 1812
mem[62638] = 5207143
在应用掩码后,我得到一个由第四个内存项(mem[49386]=7440645)的值之和关闭的和。应用掩码生成正确的值(我使用其他人发布的成功算法进行了检查)。由于某种原因,我的算法复制了这个地址。我真的怀疑这一点:

  def flip_bits(acc, []), do: acc

  def flip_bits(acc, [x | rest]) do
    acc
    |> Enum.flat_map(fn digits ->
      [List.update_at(digits, x, fn _ -> 1 end), List.update_at(digits, x, fn _ -> 0 end)]
    end)
    |> flip_bits(rest)
  end
acc的初始值是一个列表,其中包含在将一个掩码和填充应用到长度36之后的二进制原始地址的数字列表。参数[x | rest]是掩码中标识“x”的索引列表

我无法理解这一个被复制的内存地址的特殊之处。如果我删除一个地址,我得到的答案与成功的算法相同。当我使用整个数据集时,我的解决方案的偏差不仅仅是这一个条目的值,因此问题显然不仅仅是这个值。我希望有人能帮我找出这个条目有问题的原因,这样我就能理解我的逻辑中的缺陷,它产生了我目前认为是随机错误的东西

完整代码如下:

defmodule Day14 do
  use Bitwise
  @moduledoc false

  @input File.read!("lib/input")

  def process(version \\ 1) do
    @input
    |> String.split("mask = ", trim: true)
    |> Enum.map(fn line -> process_line(line, version) end)
  end

  def process_line(line, version) do
    line
    |> String.split("\n", trim: true)
    |> Enum.with_index()
    |> Enum.reduce({[]}, fn {sub, ndx}, acc ->
      case ndx do
        0 ->
          sub
          |> process_mask(version)
          |> process_helper(0, acc)

        _ ->
          sub
          |> process_mem_assign(version)
          |> process_helper(acc)
      end
    end)
  end

  def process_mask(mask, 2) do
    one_mask = mask |> String.replace("X", "0")
    xs =
      mask
      |> String.codepoints()
      |> Enum.with_index()
      |> Enum.filter(&Kernel.==(elem(&1, 0), "X"))
      |> Enum.map(&elem(&1, 1))

    {one_mask, xs}

  end

  def process_mem_assign(sub, _version) do
    Regex.scan(~r/(?<=mem\[)\d+|(?<=]\s=\s)\d+/, sub)
    |> List.flatten()
    |> Enum.with_index()
    |> Enum.map(fn {match, _ndx} -> String.to_integer(match) end)
    |> List.to_tuple()
  end

  def process_helper(matches, 0, acc) do
    Tuple.insert_at(acc, 0, matches)
  end

  def process_helper(matches, {mask, assignments}) do
    {mask, [matches | assignments]}
  end

  def initialize(version \\ 1) do
    process(version)
    |> build_mem_map(version)
  end

  def build_mem_map(processed_lines, version \\ 1) do
    processed_lines
    |> Enum.reduce(%{}, fn {mask, assignments}, memory ->
      assign_memory(mask, assignments, memory, version)
    end)
  end

  def assign_memory(masks, assignments, memory, 2 = version) do
    assignments
    |> Enum.map(&apply_mask(&1, masks, version))
    |> Enum.reduce(memory, fn {addresses, val}, acc ->
      update_memory({addresses, val}, acc, version)
    end)
  end

  def apply_mask({address, value}, {one_mask, xs}, 2) do
    len = one_mask |> String.length()

    one_masked = (address ||| String.to_integer(one_mask, 2)) |> Integer.digits(2)

    {flip_bits(
       [
         1..(len - length(one_masked))
         |> Enum.reduce(one_masked, fn _, acc -> [0 | acc] end)
       ],
       xs
     ), value}

  end

  def flip_bits(acc, []) do
    acc
  end

  def flip_bits(acc, [x | rest]) do
    acc
    |> Enum.flat_map(fn digits ->
      [List.update_at(digits, x, fn _ -> 1 end), List.update_at(digits, x, fn _ -> 0 end)]
    end)
    |> flip_bits(rest)
  end

  def update_memory({addresses, val}, memory, 2) do
    addresses
    |> Enum.reduce(memory, fn address, acc ->
      Map.put(acc, Integer.undigits(address, 2), val)
    end)
  end

  def run2 do
    initialize(2)
    |> sum_memory()
    |> IO.puts()
  end

  def sum_memory(mem_map) do
    mem_map
    |> Map.values()
    |> Enum.sum()
  end
end

Day14.run2()
defmodule Day14 do
按位使用
@模假
@输入文件.read!(“库/输入”)
def进程(版本\\1)执行
@输入
|>String.split(“mask=,trim:true)
|>枚举映射(fn行->进程行(行,版本)结束)
结束
def过程_线(线、版本)do
线
|>String.split(“\n”,trim:true)
|>带有_索引()的枚举
|>Enum.reduce({[]},fn{sub,ndx},acc->
案例ndx-do
0 ->
附属的
|>进程屏蔽(版本)
|>流程辅助程序(0,acc)
_ ->
附属的
|>进程\成员\分配(版本)
|>过程助理(acc)
结束
(完)
结束
def过程屏蔽(屏蔽,2)do
一个掩码=掩码>字符串。替换(“X”,“0”)
xs=
面具
|>String.codepoints()
|>带有_索引()的枚举
|>枚举筛选器(&Kernel.==(元素(&1,0),“X”))
|>枚举映射(&elem(&1,1))
{one_mask,xs}
结束
def流程成员分配(子版本)do
正则表达式扫描(~r/(?带有_索引的枚举)()
|>映射(fn{match,\u ndx}->String.to_integer(match)end)
|>List.to_tuple()
结束
def process_helper(匹配、0、acc)do
元组。在(acc,0,匹配项)处插入
结束
def process_helper(匹配,{mask,assignments})do
{掩码,[匹配|赋值]}
结束
def初始化(版本\\1)执行
过程(版本)
|>构建内存映射(版本)
结束
def build_mem_映射(已处理的线,版本\\1)执行
加工线
|>Enum.reduce(%{},fn{mask,assignments},memory->
分配内存(掩码、分配、内存、版本)
(完)
结束
def分配_内存(掩码、分配、内存,2=版本)do
作业
|>枚举映射(&apply_掩码(&1,掩码,版本))
|>reduce(内存,fn{地址,val},acc->
更新内存({地址,val},acc,版本)
(完)
结束
def apply_mask({address,value},{one_mask,xs},2)do
len=one_mask |>String.length()
一个|掩码=(地址| |字符串.到|整数(一个|掩码,2))|>整数.位数(2)
{flip_位(
[
1..(长度(一个遮罩))
|>枚举减少(一个掩码,fn,acc->[0 | acc]end)
],
xs
),值}
结束
def翻转位(acc,[])do
行政协调会
结束
def翻转位(acc、[x | rest])do
行政协调会
|>枚举平面图(fn位数->
[列表。更新位置(数字,x,fn->1结束),列表。更新位置(数字,x,fn->0结束)]
(完)
|>翻转位(剩余)
结束
def update_内存({地址,val},内存,2)do
地址
|>枚举减少(内存、fn地址、acc->
Map.put(acc,Integer.undigits(地址,2),val)
(完)
结束
def run2 do
初始化(2)
|>求和内存()
|>IO.puts()
结束
定义和内存(内存映射)do
记忆地图
|>Map.values()
|>Enum.sum()
结束
结束
第14天运行2()

我发现这一位中至少有一个问题:

  def flip_bits(acc, []), do: acc

  def flip_bits(acc, [x | rest]) do
    acc
    |> Enum.flat_map(fn digits ->
      [List.update_at(digits, x, fn _ -> 1 end), List.update_at(digits, x, fn _ -> 0 end)]
    end)
    |> flip_bits(rest)
  end
[
1..(长度(一个遮罩))
|>枚举减少(一个掩码,fn,acc->[0 | acc]end)
]
您试图用0填充
len
,但是如果
长度(一个掩码)
等于
len
,那么您将得到
1..0
,这相当于
[1,0]

iex(28)>1..0 |>Enum.to_列表
[1, 0]
您只需使用
max
从底部限制此数字:

1..max(1,长度(一个屏蔽))

我发现这一位中至少有一个问题:

  def flip_bits(acc, []), do: acc

  def flip_bits(acc, [x | rest]) do
    acc
    |> Enum.flat_map(fn digits ->
      [List.update_at(digits, x, fn _ -> 1 end), List.update_at(digits, x, fn _ -> 0 end)]
    end)
    |> flip_bits(rest)
  end
[
1..(长度(一个遮罩))
|>枚举减少(一个掩码,fn,acc->[0 | acc]end)
]
您试图用0填充
len
,但是如果
长度(一个掩码)
等于
len
,那么您将得到
1..0
,这相当于
[1,0]

iex(28)>1..0 |>Enum.to_列表
[1, 0]
您只需使用
max
从底部限制此数字:

1..max(1,长度(一个屏蔽))

只是猜测-当您在
上拆分时“\n”
您确定所有输入文件的换行符都没有添加奇数的回车符吗?输入文件看起来很干净,但即使没有,额外的回车符也会生成一个空字符串,该字符串将被修剪掉。只是猜测-当您在
上拆分时“\n”
您确定所有输入文件的换行符都没有添加奇数回车符吗?输入文件看起来很干净,但即使没有,额外的回车符也会生成一个空字符串,该字符串将被删除。