您可以使用尾遞歸來實現:
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
該解決方案比其他er解決方案提出。我寫了下面的模塊能夠標杆不同的解決方案:
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
所以對於小名單的bechmark如下:
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]
結果是以微秒爲單位的平均運行時間,並且越少越好。正如你所看到的,在這種情況下,好的ol'尾遞歸(Benchmark.alex/1
)做得更好。
我希望這個幫助:)
一個重要的問題是:當原始列表中有奇數個元素時,你想要發生什麼?例如,刪除最後一個值或爲其分配一個默認值「nil」?在所有使用'Enum.chunk'的解決方案中,您可以通過'Enum.chunk(2,2,[nil])'提供默認值,而普通的'Enum.chunk(2)'將放棄無法完全填充的塊。 –