Reputation: 8318
In my quest to find a good solution for List possible train routes on a given model railway I try to tackle this:
# 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"}
}
]
My problem: I want to write a function list_routes/2
which has trains
and train_stations
as parameter. It should return with a list of maps (one start
and one end
) which represent all possible routes on the given model railway. I'm mentally stuck in OO Ruby land and can not figure out how to solve this in a functional way.
I want to run through all station_permutations
and match them to the trains
. Once for start
and once for end
.
In Ruby I would do that with a loop. In Elixir that doesn't work. I guess that Enum.reduce
and Map.update
is the way to go. But is it and how can I cascade those?
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
Upvotes: 0
Views: 41
Reputation: 2001
First I would compute all possible states of the trains:
possible_states = Enum.map(stations_permutations, &Enum.zip(trains, &1))
Then I would loop over those states, in a double loop, one for the starting state, the other for the ending state:
for state_start <- possible_states, state_end <- possible_states do
%{start: state_start, end: state_end}
end
If you really want to use reduce
for learning purposes then:
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)
Note the initial accumulator for the outer loop is []
whereas the inner loop receives the current accumulator acc
.
Upvotes: 1