简体   繁体   中英

elixir: order a list of numbers without built-in sort function

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.

Below is an extremely inefficient but probably the simplest solution with Enum.split_while/2

Enum.reduce(list, [], fn x, acc ->
  {pre, post} = Enum.split_while(acc, & &1 < x)
  pre ++ [x] ++ post
end)

It looks like homework, so there is a huge room for improvement. For the reference, one might pick up any of existing sorting algorithms and implement any of them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM