あなたがこれを達成するために末尾再帰を使用することができます。
を
defmodule Test do
def f(list, acc \\ [])
def f([x, y | xs], acc), do: f(xs, [{x, y} | acc])
def f(_, acc), do: Enum.into(acc, %{})
end
このソリューションは、解決策が提案されました。だから、小さなリストのbechmarkは以下の通りです
defmodule Benchmark do
# My solution
def alex(xs, acc \\ [])
def alex([x, y | xs], acc), do: alex(xs, [{x, y} | acc])
def alex(_, acc), do: Map.new(acc)
# nietaki's solution
def nietaki(xs) do
xs
|> Enum.chunk(2)
|> Enum.map(fn [x, y] -> {x, y} end)
|> Map.new()
end
# Sheharyar's solution
def sheharyar(xs) do
xs
|> Enum.chunk(2)
|> Map.new(fn [x, y] -> {x, y} end)
end
# Your solution
def chip(xs) do
Enum.reduce(xs, %{}, fn(item, acc) ->
case Map.get(acc, :last) do
nil ->
Map.put(acc, :last, item)
last ->
acc = Map.put(acc, item, last)
Map.drop(acc, [:last])
end
end)
end
# Patrick's solution
def patrick(xs) do
xs
|> Enum.chunk(2)
|> Enum.into(%{}, fn [x, y] -> {x, y} end)
end
# Function to do the time benchmarks.
def timed(f, list, times \\ 10) do
tests =
for _ <- 0..times do
:timer.tc(fn -> apply(__MODULE__, f, [list]) end) |> elem(0)
end
avg = Enum.sum(tests)/times
{f, avg}
end
# Test function.
def test(list, times \\ 10) do
list = Enum.to_list(list)
[:alex, :chip, :patrick, :nietaki, :sheharyar]
|> Enum.map(fn f -> timed(f, list, times) end)
|> Enum.sort(fn {_, x}, {_, y} -> x < y end)
end
end
:
iex(1)> Benchmark.test(0..4)
[alex: 0.2, nietaki: 0.5, sheharyar: 0.6, chip: 0.8, patrick: 4.4]
そして、次の大規模なリストのために:
iex(2)> Benchmark.test(0..1_000_000)
[alex: 143105.7, nietaki: 241233.4, sheharyar: 254751.9, patrick: 501678.9, chip: 801616.5]
私は別のソリューションベンチマークのことができるようにするには、以下のモジュールを書きました
結果は平均実行時間(マイクロ秒)で、それ以下の方が良いです。あなたが見ることができるように、この場合、良いオールテイル再帰(Benchmark.alex/1
)が良い仕事をします。
私はこのヘルプ:) Enum.into
を使用して
重要な質問の1つは、元のリストに奇数の要素がある場合に、何をしたいのですか?最後の値を削除するか、例えば 'nil'のデフォルト値を代入しますか? 'Enum.chunk'を使用するすべてのソリューションでは、' Enum.chunk(2、2、[nil]) 'を介してデフォルト値を与えることができますが、普通の' Enum.chunk(2) 'は完全には満たされない。 –