small medium large xlarge

• Write a function MyList.span(from, to) that returns a list of the numbers from `from` up to `to`.

A Possible Solution</summary>

```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)
```

</details>

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
``````

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.

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
``````

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
``````

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
``````

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) ]
``````

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
``````

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
``````
``````defmodule Spanner do
def span(a,a), do: [a]
def span(a,b) when b < a, do: [a|span(a-1,b)]
def span(a,b),            do: [a|span(a+1,b)]
end
``````

Hmm. I built my list the other way - just kept adding to the head:

``````	def span(a,b), do: _span(a,[b])

end
end
``````

No protections against bad inputs, of course, but it does the job fairly simply. Is there any reason not to build a list backwards (tail to head)?

I build the result list and track it as a separate argument. Not as efficient as Geoffrey Barto above.

As a matter of fact, I suspect the new_list++[from] expression is probably expensive since it has to traverse the list to get to the end.

``````defmodule MyList do
def span(from, to), do: _span([ from | to ], [])
defp _span([ from | to ], new_list) when(from <= to) do
_span( [from + 1 | to], new_list ++ [from] )
end
defp _span([ _| _], new_list), do: new_list
end
``````

Well, I came up with this where I built the list from tail to head. I would like to know if this is a bad practice in anyway.

``````defmodule MyList do
def span(from, to) when from > to, do: []
def span(from, to), do: _span([to], from, to)
defp _span(list = [head | _], from, _to) when head == from, do: list
defp _span(list = [head | _], from, to), do: _span([head-1|list], from, to)
end
``````
``````defmodule MyList do
def span(from, to), do: _span(from, to-1,[to])
defp _span(from, from, list), do: list
defp _span(from, to, list), do: _span(from, to-1, [to-1|list])
end
``````

Upside down:

```defmodule MyList do
def span(from, to) when from > to do [] end
def span(from, to) do span(from, to - 1) ++ [to] end
end
```

Haven’t tried breaking it yet but it looks pretty much the same as Gabe’s.

```defmodule Span do
def span(to, to), do: [to]
def span(from, to), do: [from | span(from + 1, to)]
end
```

My solution was a bit different.

``````defmodule Span do
def from(top, bottom) do
range = top..bottom
for n <- range do
IO.puts n
end
range
end
end
``````
``````def span_list(from, to), do: span(from, to, [to])

defp span(from, to, [h | t]) when h > from, do: span(from, to - 1, [to - 1, h | t])

defp span(from, to, acc) when to == from, do: acc
``````

My solution :

``````defmodule MyList do
def span(from, to) do, _span(from..to, [])
defp _span(from..to, list) when from < to, do: _span(from + 1..to, list ++ [from])
defp _span(from..to, list) when from == to, do: list
end
``````

I need to improve my solution

My solution

``````
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)]
def span(from, to) when from < to, do: [from | span(from + 1, to)]
end

IO.inspect MyList.span(1,10)
IO.inspect MyList.span(10,1)

``````

Output

``````[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
``````

My solution:

``````defmodule MyList do

def span(from, to) when from < to, do: [from | span(from+1, to)]
def span(from, to) when from > to, do: [from | span(from-1, to)]
def span(from, to) when from === to, do: [to]

end
``````

Why not keep it simple? :)

``````def span(from,to), do: from..to |> Enum.to_list
``````

My actual solution was really close to some others I saw here:

``````  def span(to,to), do: [to]
def span(from,to) when to > from, do: [from|span(from+1,to)]
def span(from,to) when to < from, do: [from|span(from-1,to)]
``````
```def span(x,x), do: [x]

def span(x,y) when x < y do
[x|span(x+1, y)]
end

def span(x,y) when x > y do
[x|span(x-1, y)]
end
```

I got a little carried away and made mine work backwards as well:

``````def span(to, to), do: [to]
def span(from, to) when from < to, do: [ from | span(from + 1, to) ]
def span(from, to), do: [ from | span(from - 1, to) ]
``````
``````defmodule MyList do

def span(to, to), do: [to]
def span(from, to), do: [from | span(from + 1, to)]

end
``````

Mehdi, your code is short and elegant so I tried it, but it fail when from > to (I know it is not the point of the exercise).

I also tried to protect runtime against bad arguments, so I used private functions to keep my code DRY with the guard clause when is_integer(from) and is_integer(to).

``````defmodule MyList do

def span(from,to) when is_integer(from) and is_integer(to), do: _span(from,to)

defp _span(from,to) when from > to, do: []
defp _span(from,to), do: [from|_span(from+1,to)]

end
``````

Using Enum:

``````  def span(from, to), do: Enum.to_list(from..to)
``````

Without Enum:

``````  def alt_span(to, to), do: [to]
def alt_span(from, to), do: [ from | alt_span(from + 1, to ) ]
``````

More flexible to allow greatest to least

``````  # in the same module as alt_span
def flex_span(to, to), do: [to]
def flex_span(from, to) when from <= to, do: alt_span(from, to)
def flex_span(from, to) when from >= to, do: [ from | flex_span(from - 1, to ) ]
``````

I know the chapter was all about recursion, but I just used some built-ins to solve this:

``````defmodule MyList do
def span(from, to), do: Enum.to_list(from..to)
end
``````

That will handle the exercise as well as numbers where from > to by creating a list with the numbers going backwards.

Here’s my solution:

```  def span(from, to) when from < to do
[from | span(from+1, to)]
end

def span(from, to) when from == to do
[to]
end

def span(from, to) when from > to do
raise "args 1 must be less than or equal args 2"
end

```

Another one:

``````defmodule MyList do
def span(to, to), do: [to]

def span(from, to) when from < to do
[ from | span( from+1, to ) ]
end

def span(from, to)  do   # from > to
[ from | span( from-1, to ) ]
end
end

``````

Alternative solution, using Enum:

``````defmodule MyList do
def span(to, to), do: [to]
def span(from, to) when from < to, do: Enum.to_list(from..to)
def span(from, to), do: Enum.to_list(from..to)
end

#For both solutions - calling the func:
IO.inspect MyList.span(1, 1)   #=> [1]
IO.inspect MyList.span(1, 10)  #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
IO.inspect MyList.span(10, 1)  #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
``````

my modest solution:

``````defmodule Mylist7 do
def span(from, to), do: _span(from, to)
defp _span(from, to) when from == to, do: []++[to]
defp _span(from, to) when from < to do
acc = from + 1
[from | _span(acc, to)]
end
defp _span(from, to) when from > to do
IO.puts "Error, from is more as to"
end
end
``````

and this is a result of searching of elixir library, very concise and powerful :-)

``````defmodule Mylist6 do
def span(from, to), do: Enum.concat([from..to])
end
``````
``````defmodule MyList do

def span(from, to), do: Enum.to_list from..to

end
``````

Same as Richard - works when from is not greater than to.

``````defmodule MyList do
def span(from, to), do: do_span(from, to, [])
defp do_span(to, to, acc) do
[to | acc]
|> Enum.reverse
end
defp do_span(from, to, acc) when from < to do
do_span(from + 1, to, [ from | acc ])
end
defp do_span(from, to, acc) when from > to do
do_span(from - 1, to, [ from | acc ])
end
end
``````

Adding my solution. Tail call optimized to test that out. Reverse is just for proper ordering.

A different solution.

``````defmodule MyList do
def span(from, to), do: _span([], from, to)

defp _span(list, from, to) when to < from, do: list
defp _span(list, from, to), do: _span([to | list], from, to - 1)
end
``````
``````defmodule MyList do
def span(from, to)
when from < to,
do: [from | span(from+1, to)]

def span(_from, to), do: [to | []]
end
``````
``````defmodule MyList do
def span(to, to), do: []
def span(from, to) when from < to do
[from | span(from+1, to)]
end
def span(from, to) when from > to do
[from | span(from-1, to)]
end
end
``````
``````defmodule MyList do
def span(to, to), do: []
def span(from, to), do: [from | span(from+1,to)]
end
``````

I didn’t handle the case where `from > to` but that would be easy enough to do by modifying the first line. Just posting my mistakes as a learning experience.

One thing that’s slightly unclear to me is if the list returned should be “`from` to-but-not-including `to`”. In other words `MyList.span(1,5)` should return `[1,2,3,4]`. I’ve coded my solution this way.

``````defmodule MyList do

def reverse(list), do: _reverse(list, [])
def _reverse([], rev), do: rev

def span(to, to), do: [to]
def span(from, to) when from < to, do: [from|span(from + 1, to)]·
def span(from, to) when from > to, do: reverse([to|span(to + 1, from)])

end
``````

``````MyList.span(1, 5) == [1, 2, 3, 4, 5]
MyList.span(5, 1) == [5, 4, 3, 2, 1]
MyList.span(-5, -1) == [-5, -4 ,-3 ,-2, -1]
MyList.span(-1, -5) == [-1, -2 ,-3 ,-4, -5]
MyList.span(-2, 2) == [-2, -1, 0, 1, 2]
MyList.span(2, -2) == [2, 1, 0, -1, -2]
``````

Here is my solution.

``````def span(from, to) when from > to, do: raise "first arg must be less than or equal to second arg"
def span(from, to) when from === to, do: [from]
def span(from, to) do
span(from, to - 1) ++ [to]
end
``````

My solution defaults to a step of 1, but also allows step of different amounts (and negative numbers). There’s a not so obvious bug in it though; if `to - from` is not a multiple of `step`, then it will never converge.

``````defmodule MyList do
def span(from, to, step \\ 1)
def span(to, to, _step), do: [to]
def span(from, to, step), do: [ from | span(from + step, to, step) ]
end

IO.inspect MyList.span(1, 10)
IO.inspect MyList.span(2, -3, -1)
IO.inspect MyList.span(0, 12, 2)
IO.inspect MyList.span(1, 12, 2) # will run forever because 12 - 1 is not a multiple of 2
``````
```defmodule MyList do
def span(from, from), do: [from]
def span(from, to) when from > to, do: [from | span(from-1, to)]
def span(from, to), do: [from | span(from+1, to)]
end
```

I found this to be the most straightforward approach:

``````defmodule MyList do
def span(to , to), do: [ to ]
def span(from, to) when from < to , do: [ from | span(from + 1, to) ]
def span(_, _), do: raise "provided From seems to be higher then To"
end
``````

Outcome:

``````iex()> MyList.span(1, 4)
[1, 2, 3, 4]
``````
```defmodule MyList do
def span(from,to) when from <= to, do: [from | span(from+1,to)]
def span(_,_), do: []
end
```

I had a similar solution to Dave’s originally, but ended up with a list which looked like this:

`[1, 2, 3, 4 | 5]`

Apparently this is an improper list should anyone else come across the same issue.

``````def span(from, to), do: _span(from, to, [true: 1, false: -1][from < to])
defp _span(n, n, _dir), do: [n]
defp _span(from, to, dir), do: [from] ++ _span(from + dir, to, dir)
``````

My solution, handling cases when from is greater than to

``````def span(from, to) when from < to do
[from | span(from+1, to)]
end

def span(from, to) when from > to do
[from | span(from-1, to)]
end

def span(from = _, _) do
[from]
end
``````

Here’s my implementation:

``````defmodule MyList do
def span(from, to) when from > to, do: _span(
from,
to,
&(&1 - 1)
)

def span(from, to), do: _span(
from,
to,
&(&1 + 1)
)

defp _span(from, to, f), do: _span(from, to, f, [ from ])

defp _span(to, to, _f, list), do: Enum.reverse(list)

defp _span(from, to, f, list) do
with x = f.(from),
do:  _span(x, to, f, [ x | list ])
end
end

``````
`````` def span(a, a),            do: [a]
def span(a, b) when a > b, do: [a | span(a - 1, b)]
def span(a, b),            do: [a | span(a + 1, b)]
``````
``````
defmodule MyList do

# span1 is a solution using Enum.map

def span1(from,to) when from > to do
IO.puts("the first argument must be smaller than the second")
end
def span1(a,b) do
Enum.map(a..b, &(&1))
end

# span2 is a solution using recursion
def span2(a,a) do
[a]
end

def span2(from,to) when from > to do
IO.puts("the first argument must be smaller than the second")
end

def span2(from,to) do
[from] ++ span2(from+1,to)
end

end

``````
``````defmodule MyList do
def span(from, to) when from <= to do
[from | span(from + 1, to)]
end
def span(_from, _to), do: []
end
``````
You must be logged in to comment