Elixir/Erlang:使用静态表快速查找

Tom*_*ner 4 erlang lookup-tables elixir

在我的应用程序中,我需要将整数转换为某个术语; 例如:

1 ? :red
2 ? :green
3 ? :blue
Run Code Online (Sandbox Code Playgroud)

该表是静态的,在编译期间是已知的,其索引范围为<1,n>.其中约有60个.

以何种方式表示表,因此查找速度最快?Dict,HashDict,元组(与kernel.elem()),ets,函数与模式匹配......?

Szy*_*Jeż 8

正如Julius Beckmann在这种情况下建议的那样,具有模式匹配的功能应该足够,因为根据我的测量,它比访问地图快5倍.

您可以在下面找到您要查找的内容的实现(底部包含基准代码):

defmodule TermLookUpByInteger do
  @term_by_integer %{
    1 => :aa, 11 => :ba, 21 => :ca, 31 => :da, 41 => :ea, 51 => :fa, 61 => :ga,
    2 => :ab, 12 => :bb, 22 => :cb, 32 => :db, 42 => :eb, 52 => :fb, 62 => :gb,
    3 => :ac, 13 => :bc, 23 => :cc, 33 => :dc, 43 => :ec, 53 => :fc, 63 => :gc,
    4 => :ad, 14 => :bd, 24 => :cd, 34 => :dd, 44 => :ed, 54 => :fd, 64 => :gd,
    5 => :ae, 15 => :be, 25 => :ce, 35 => :de, 45 => :ee, 55 => :fe, 65 => :ge,
    6 => :af, 16 => :bf, 26 => :cf, 36 => :df, 46 => :ef, 56 => :ff, 66 => :gf,
    7 => :ag, 17 => :bg, 27 => :cg, 37 => :dg, 47 => :eg, 57 => :fg, 67 => :gg,
    8 => :ah, 18 => :bh, 28 => :ch, 38 => :dh, 48 => :eh, 58 => :fh, 68 => :gh,
    9 => :ai, 19 => :bi, 29 => :ci, 39 => :di, 49 => :ei, 59 => :fi, 69 => :gi,
    0 => :aj, 10 => :bj, 20 => :cj, 30 => :dj, 40 => :ej, 50 => :fj, 60 => :gj,
  }

  @doc """
    iex> TermLookUpByInteger.lookup_pmf(2)
    :ab
  """
  def lookup_pmf(int), do: do_lookup(int)

  for {int, term} <- @term_by_integer do
    defp do_lookup(unquote(int)), do: unquote(term)
  end

  @doc """
    iex> TermLookUpByInteger.lookup_m(3)
    :ac
  """
  def lookup_m(int), do: @term_by_integer[int]
end

# Benchmark:

n = 1_000_000
range = 1..(n)
measure = fn fun -> :timer.tc(fn -> for _ <- range, do: fun.() end) end
{time_pmf, _result} = measure.(fn -> TermLookUpByInteger.lookup_pmf(:random.uniform(60)) end)
{time_m, _result}   = measure.(fn -> TermLookUpByInteger.lookup_m(:random.uniform(60)) end)

IO.puts "                      Sample size: #{n}"
IO.puts "Pattern matching functions lookup: #{time_pmf/1000} ms"
IO.puts "                       Map lookup: #{time_m/1000} ms"
IO.puts "              Absolute Difference: #{(time_pmf-time_m)/1000} ms"
IO.puts "              Relative Difference: #{round((time_pmf-time_m)/time_m*100)}%"
IO.puts "                           Faster: x #{Float.round(time_m/time_pmf, 2)} times"
Run Code Online (Sandbox Code Playgroud)

结果:

                      Sample size: 1000000
Pattern matching functions lookup: 447.6 ms
                       Map lookup: 2423.517 ms
              Absolute Difference: -1975.917 ms
              Relative Difference: -82%
                           Faster: x 5.41 times
Run Code Online (Sandbox Code Playgroud)

我希望这会有用.


h4c*_*4cc 5

如果地图是完全静态且不会更改,则可以使用生成的模式匹配.这将是在应用程序中集成该查找的最快方法.

一些示例代码,从外部文件中读取这些映射:https://github.com/h4cc/slugger/blob/master/lib/slugger.ex#L69-72 您可以使用源地图数据而不是使用外部文件举行了@attribute.

即使在运行时需要新的映射,也可以使用在HashDict中进行查找的catchall模式匹配来处理这些映射.