级联枚举。reduce/3 和地图。update/4

Cascade Enum.reduce/3 and Map.update/4

在我为 寻找一个好的解决方案的过程中,我尝试解决这个问题:

# This is the data I have.
#
trains = [:red_train, :blue_train]
train_stations = ["Station 1", "Station 2"]

# This stepping stone is calculated by a function.
#
stations_permutations = [
    ["Station 1", "Station 2"], 
    ["Station 2", "Station 1"]
]

# This should be the result.
#
possible_routes = 
    [
    %{
        end: %{blue_train: "Station 2", red_train: "Station 1"},
        start: %{blue_train: "Station 2", red_train: "Station 1"}
    },
    %{
        end: %{blue_train: "Station 1", red_train: "Station 2"},
        start: %{blue_train: "Station 1", red_train: "Station 2"}
    },
    %{
        end: %{blue_train: "Station 1", red_train: "Station 2"},
        start: %{blue_train: "Station 2", red_train: "Station 1"}
    },
    %{
        end: %{blue_train: "Station 2", red_train: "Station 1"},
        start: %{blue_train: "Station 1", red_train: "Station 2"}
    }
    ]

我的问题:我想写一个函数list_routes/2,它有trainstrain_stations作为参数。它应该 return 带有地图列表(一张 start 和一张 end),代表给定模型铁路上所有可能的路线。我在精神上陷入了 OO Ruby 领域,无法弄清楚如何以实用的方式解决这个问题。

我想 运行 遍历所有 station_permutations 并将它们匹配到 trains。一次用于 start 一次用于 end.

在Ruby中我会用一个循环来做。在 Elixir 中这是行不通的。我想 Enum.reduceMap.update 是要走的路。但它是吗?我该如何级联这些?

def station_permutations(_train_stations) do
  [
    ["Station 1", "Station 2"], 
    ["Station 2", "Station 1"]
  ]
end

@doc """
Returns a list of all possible routes.

## Examples
    iex> Trains.list_routes([:red_train, :blue_train], ["Station 1", "Station 2"])
    [
      %{
        end: %{blue_train: "Station 2", red_train: "Station 1"},
        start: %{blue_train: "Station 2", red_train: "Station 1"}
      },
      %{
        end: %{blue_train: "Station 1", red_train: "Station 2"},
        start: %{blue_train: "Station 1", red_train: "Station 2"}
      },
      %{
        end: %{blue_train: "Station 1", red_train: "Station 2"},
        start: %{blue_train: "Station 2", red_train: "Station 1"}
      },
      %{
        end: %{blue_train: "Station 2", red_train: "Station 1"},
        start: %{blue_train: "Station 1", red_train: "Station 2"}
      }
    ]
"""
def list_routes(trains, train_stations) do
  station_permutations(train_stations)
  |> Enum.reduce(%{}, fn stations, acc ->
    Map.update(acc, stations, nil, ???????)
  end)
end

首先我会计算火车的所有可能状态:

possible_states = Enum.map(stations_permutations, &Enum.zip(trains, &1))

然后我会循环这些状态,在一个双循环中,一个用于起始状态,另一个用于结束状态:

for state_start <- possible_states, state_end <- possible_states do
  %{start: state_start, end: state_end}
end

如果您真的想 reduce 用于学习目的,那么:

Enum.reduce(possible_states, [], fn state_start, acc ->
  Enum.reduce(possible_states, acc, fn state_end, acc ->
    [%{start: state_start, end: state_end} | acc]
  end)
end)

注意外循环的初始累加器是 [] 而内循环接收当前累加器 acc