【问题标题】:elixir: order a list of numbers without built-in sort functionelixir:对没有内置排序功能的数字列表进行排序
【发布时间】:2021-10-04 18:07:27
【问题描述】:

如果我有一个每次长度都不同的列表,并且我想将其从低到高排序,我该怎么做?

如果我有:[-5, -23, 5, 0, 23, 0.7, -6, 23, 67]

我要:[-23, -6, -5, 0, 0.7, 5, 23, 23, 67]

我尝试使用 for 循环来迭代列表并创建一个新列表来接收数字,但看起来它不起作用。也许我可以改用Enum 函数,但我真的没有这个想法。

【问题讨论】:

  • 题主说“没有内置排序功能”,是不是说不想使用Enum.sort?
  • 没错,我不能用它
  • 为什么不呢?它适用于每个 Elixir 系统。你在做运动吗?排序是一个基本的计算机科学问题,所以如果你必须编写自己的算法,首先你必须选择哪一个。 Elixir 是不可变语言,其选项与可变语言不同(例如,快速排序在 Elixir 中效果不佳)。 Enum.sort 使用归并排序。
  • 是的,这是一起学习灵药和计算机科学的练习
  • 您希望有人为您编写排序算法吗?那你什么都学不到,还不如看看现有的实现。

标签: list sorting elixir elixir-iex


【解决方案1】:

如果不能使用Enum.sort,则必须实现自己的排序算法。

Elixir 是一种不可变语言,因此需要就地操作(如 Quicksort)的流行算法在 Elixir 中无法正常工作。这是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

跑步:

iex> Example.merge_sort([-5, -23, 5, 0, 23, 0.7, -6, 23, 67])
[-23, -6, -5, 0, 0.7, 5, 23, 23, 67]

只是为了好玩,这里是reversesplit,如果你根本不想使用Enum

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)

在这种情况下,我们甚至可以将{reverse(b), a}简化为{b, a},因为拆分时不需要保留项目顺序,因为无论如何都会对结果进行排序。

【讨论】:

    【解决方案2】:

    下面是一个效率极低但可能是Enum.split_while/2最简单的解决方案

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

    看起来像家庭作业,所以还有很大的改进空间。作为参考,可以选择任何现有的sorting algorithms 并实现它们中的任何一个。

    【讨论】:

    • 这真是太棒了@Aleksei_Matiushkin 但如果Enum.sort 越界,那么巧妙的Enum.split_while 可能也会如此。!无论如何,请您解释一下两个&amp;s 作为您的第二个参数的作用。
    • 这是一个函数捕获。
    猜你喜欢
    • 1970-01-01
    • 2011-01-26
    • 1970-01-01
    • 2012-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-26
    • 1970-01-01
    相关资源
    最近更新 更多