I am implementing a sorting algorithm to sort a collection of structs. I need to sort the collection on the value of a particular key in each struct. I can hard code the key into the function, but I'd like to generalize it. As you can see below, the specialized implementation is 3x faster than the generalized.
Is there a more efficient way to get the value of a key in a struct than defp get_value(x, key), do: get_in(x, [Access.key(key)])
? Which comes from the docs.
Specialized
defmodule QuickSort do
def qsort([]) do
[]
end
def qsort([pivot | rest]) do
{left, right} = Enum.partition(rest, fn(x) -> x.key < pivot.key end)
qsort(left) ++ [pivot] ++ qsort(right)
end
end
iex(74)> Benchwarmer.benchmark fn -> QuickSort.qsort(collection, :key) end
*** #Function<20.52032458/0 in :erl_eval.expr/5> ***
2.5 sec 3 iterations 863742.34 μs/op
Generalized
defmodule QuickSort do
def qsort(collection, key \\ nil)
def qsort([], _) do
[]
end
def qsort([pivot | rest], key) do
{left, right} = Enum.partition(rest, fn(x) -> get_value(x, key) < get_value(pivot, key) end)
qsort(left, key) ++ [pivot] ++ qsort(right, key)
end
defp get_value(x, key), do: get_in(x, [Access.key(key)])
end
iex(79)> Benchwarmer.benchmark fn -> QuickSort.qsort(collection, :key) end
*** #Function<20.52032458/0 in :erl_eval.expr/5> ***
3.1 sec 1 iterations 3180784.0 μs/op
defp get_value(x, key), do: x[key]
? – Dogbertdoes not implement the Access behaviour
– jdesilviodefp get_value(x, key), do: Map.get(x, key)
. Instead of a separate function, you can also just put this in theEnum.partition
's fn:Enum.partition(rest, fn(x) -> Map.get(x, key) < Map.get(pivot, key) end)
. – Dogbert