If I have a list that varies in length each time and I want to sort it from lowest to highest, how would I do that?
If I have: [-5, -23, 5, 0, 23, 0.7, -6, 23, 67]
I want: [-23, -6, -5, 0, 0.7, 5, 23, 23, 67]
I tried to use a for loop to iterate the list and create a new list to receive the numbers but doesn't look like it's gonna work. maybe i can use Enum function instead, but i'm really without ideas on this one.
If you cannot use Enum.sort, you have to implement your own sorting algorithm.
Elixir is an immutable language, so popular algorithms that require in-place operations like Quicksort do not work well in Elixir. Here is an implementation of Mergesort:
defmodule Example do
def merge_sort([]), do: []
def merge_sort([_] = list), do: list
def merge_sort(list) when is_list(list) do
len = length(list)
{a, b} = Enum.split(list, div(len, 2))
a = merge_sort(a)
b = merge_sort(b)
merge(a, b, [])
end
defp merge([], b, acc), do: Enum.reverse(acc) ++ b
defp merge(a, [], acc), do: Enum.reverse(acc) ++ a
defp merge([a_head | a_tail] = a, [b_head | b_tail] = b, acc) do
if a_head <= b_head do
merge(a_tail, b, [a_head | acc])
else
merge(a, b_tail, [b_head | acc])
end
end
end
Running:
iex> Example.merge_sort([-5, -23, 5, 0, 23, 0.7, -6, 23, 67])
[-23, -6, -5, 0, 0.7, 5, 23, 23, 67]
Just for fun, here is reverse and split, if you don't want to use Enum at all:
defp reverse(list), do: reverse(list, [])
defp reverse([], acc), do: acc
defp reverse([h | t], acc), do: reverse(t, [h | acc])
defp split(list, n), do: split(list, [], n)
defp split(a, b, 0), do: {reverse(b), a}
defp split([h | a], b, n), do: split(a, [h | b], n - 1)
We can even simplify {reverse(b), a}, to {b, a} in this case, because there's no need to preserve the item order when splitting, since the result gets sorted anyway.