16 Jul 2013, 02:25 Dave Thomas (338 posts) Write a function MyList.span(from, to) that returns a list of the numbers from `from` up to `to`. A Possible Solution ```defmodule MyList do def span(from, to) when from > to, do: [] def span(from, to) do [ from | span(from+1, to) ] end end IO.inspect MyList.span(5, 10) ``` 05 Aug 2013, 22:01 Garry Watkins (1 post) Dave, you need to watch out for tail recursion (the last operation is not the recursive function call). You should use an accumulator then reverse it. It is much more efficient. ``````defmodule MyList do def span(from, to) when from <= to do _span(from, to, [from]) end def span(from, to) do span(to, from) end defp _span(from, to, acc) when from == to do acc |> :lists.reverse end defp _span(from, to, acc) do x = from + 1 _span(x, to, [x | acc]) end end `````` 08 Aug 2013, 19:05 Dave Thomas (338 posts) Just how much more efficient for a typical case, though? I agree in general, but I have an interesting experience. When I first started coding elixir, I tried hard to be tail recursive. But when I posted that code, beginners said it was confusing, and experienced Erlang and Elixir programmers said it probably wasn’t necessary. So I now treat writing tail recursive code as an optimization, and like more optimizations, I do it only if I find I need to. 22 Aug 2013, 08:59 Gabe Hollombe (2 posts) My version ended up being very similar to @Dave’s above. The only difference is that I used pattern matching in the arguments list instead of a `when` clause. I don’t think this is easier to read than using `when` but do other folks have an opinion here on which is more idiomatic Elixir? ``````defmodule MyList do def span(_from=to, to), do: [to] def span(from, to), do: [ from | span(from + 1, to) ] end `````` 03 Sep 2013, 20:41 Aleksey Gureiev (8 posts) Gabe, you aren’t looking out for “from” being greater than “to”. If you go down that path, I would recommend doing it like: ``````defmodule T do def span(to, to), do: [ to ] def span(from, to) when from < to, do: [ from | span(from + 1, to) ] end `````` 25 Sep 2013, 04:49 I did as @AlekseyGureiev. But, did not handled case when: from > to ``````defmodule MyList do def span(from, to) when from == to, do: [from] def span(from, to) when from < to, do: [from | span(from + 1, to)] end `````` 27 Jan 2014, 14:00 Alan Gardner (6 posts) I started with … ``````def span(from, to), do: Enum.to_list(from..to) `````` but then realised that was cheating ;) Ended up with … ``````def span(to, to), do: [to] def span(from, to) when from > to, do: span(to, from) def span(from, to), do: [ from | span(from + 1, to) ] `````` 16 May 2014, 01:24 Roumen Roupski (1 post) One more solution: ``````defmodule MyList do def span(to, to), do: [to] def span(from, to) when from < to, do: _span(from, to, []) def span(from, to), do: _span_r(to, from, []) defp _span(to, to, acc), do: [to | acc] defp _span(from, to, acc), do: _span(from, to - 1, [to | acc]) defp _span_r(to, to, acc), do: [to | acc] defp _span_r(from, to, acc), do: _span_r(from + 1, to, [from | acc]) end `````` 09 Jul 2014, 08:35 Patrick Oscity (6 posts) Here’s a recursive definition that can handle reverse ranges such as 10..1: ``````defmodule MyList do def span(from, from), do: [from] def span(from, to), do: [from | span(_next(from, to), to)] defp _next(from, to) when from < to, do: from + 1 defp _next(from, _to), do: from - 1 end MyList.span 10, 1 #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] `````` Alternative solution, using a range and Enum.map: ``````defmodule MyList do def span(from, to), do: Enum.map(from..to, &(&1)) end `````` You must be logged in to comment