【问题标题】:Fast case-insensitive sorting in ElixirElixir 中的快速不区分大小写排序
【发布时间】:2018-08-10 21:39:29
【问题描述】:

Elixir 程序员们好。

我有大约 2.500 首音乐曲目的列表,我想按不同的参数(例如曲目的标题)进行排序。

排序应该不区分大小写。

下面的代码可以工作,但需要大约 100 毫秒到 130 毫秒来对列表进行排序。有更快的方法吗?我的一个参考是 Node.js,它在使用 Array.prototype.sort 时在大约 25 毫秒内完成。

编辑:对不起,我实际上放错了时间。排序发生在大约 30 毫秒内。不过,我还是想听听你的意见:排序能不能快点?

谢谢。

defmodule MusicServer.Tracks.SortTracks do
  def sort_tracks(tracks, "title", "desc") do
    Enum.sort(tracks, fn track1, track2 ->
      first_char(track1["title"]) <= first_char(track2["title"])
    end)
  end

  def first_char(string) do
    string
    |> String.at(0)
    |> String.downcase()
  end
end

数据结构示例:

[
  %{
    "artist" => "Rolling Stones",
    "title" => "Start It Up",
    "bpm" => 100,
    "createdAt" => "2018-04-27T09:08:04.428Z",
    "updatedAt" => "2018-07-14T14:28:17.771Z"
  },
  %{
    "artist" => "Al Green",
    "title" => "Let's Stay Together",
    "bpm" => 123,
    "createdAt" => "2018-04-27T09:08:04.428Z",
    "updatedAt" => "2018-07-14T14:28:17.771Z"
  },
  ...
]

【问题讨论】:

  • 你能试试计时Enum.sort_by(tracks, fn track -&gt; first_char(track["title"]) end)吗?
  • 超快!当我按照您的建议使用 Enum.sort_by 时,{time, result} = :timer.tc (fn -&gt; MusicServer.Tracks.SortTracks.sort_tracks(tracks, "title", "desc") end) 给我 7433、6969、6356(微秒)...谢谢!
  • 可读性更强!
  • 我很好奇为什么会这样。有什么想法吗,Dogbert?
  • 至少,它首先计算每个标题的第一个字符,然后开始排序github.com/elixir-lang/elixir/blob/v1.7.2/lib/elixir/lib/…

标签: elixir


【解决方案1】:

Enum.sort 将调用比较器函数n log(n) 次,这意味着first_char 将被调用2n log(n)可能 是这里的瓶颈。为了减少对first_char的调用,您可以切换到Enum.sort_by,它为每个元素调用一次函数,然后在排序时缓存其值:

Enum.sort_by(tracks, fn track -> first_char(track["title"]) end)

对于长度为 2,500 的列表,对 first_char 的调用次数将从超过 50k 减少到 2.5k。当然sort_by 必须做分配数据结构来存储计算值的工作,但对于这个输入来说它应该仍然更快。在使用它之前,您应该自己仔细对其进行基准测试!

【讨论】:

  • 对渐近(我认为我的术语正确)行为特征的认识表示敬意!
猜你喜欢
  • 1970-01-01
  • 2019-01-31
  • 2020-09-13
  • 2012-06-22
  • 1970-01-01
  • 2014-05-20
  • 2018-03-09
  • 1970-01-01
  • 2014-11-10
相关资源
最近更新 更多