I'm trying to translate the following toy dynamic programming problem to Elixir but struggling to see how to do it given there is no early return in Elixir.
It should return a valid combination from "numbers" that sum to "targetSum"
const howSum = (targetSum, numbers) => {
if (targetSum === 0) return [];
if (targetSum < 0) return null;
for (let num of numbers) {
const remainder = targetSum - num;
const remainderResult = howSum(remainder, numbers);
if (remainderResult !== null) {
return [...remainderResult, num];
}
}
return null;
}
console.log(howSum(7, [2, 3])) // [3,2,2]
I can get below the Elixir version to log all possible solutions with a list comprehension, but how can I get the function to return the first solution found and return/stop at that point?
defmodule HowSum do
@doc """
Can you make target_sum from numbers list
You can use individual numbers as many times as you like
"""
def sum(0, _numbers, _), do: []
def sum(target_sum, _numbers, _) when target_sum < 0, do: nil
def sum(target_sum, numbers, path) do
for number <- numbers do
remainder = target_sum - number
result = sum(remainder, numbers, path ++ [number])
if result == [] do
IO.inspect(path ++ [number])
end
end
end
end
UPDATE
This is my solution which doesn't seem idiomatic but works using an Agent :-)
defmodule HowSum do
def cache do
Agent.start_link(fn -> nil end, name: :solution)
end
@doc """
Can you make target_sum from numbers list
You can use individual numbers as many times as you like
"""
def sum(0, _numbers, _), do: []
def sum(target_sum, _numbers, _) when target_sum < 0, do: nil
def sum(target_sum, numbers, path) do
solution = Agent.get(:solution, & &1)
if !solution do
for number <- numbers do
remainder = target_sum - number
result = sum(remainder, numbers, path ++ [number])
if result == [] do
Agent.update(:solution, &(&1 = path ++ [number]))
end
end
end
Agent.get(:solution, & &1)
end
end