将[1,2,3,4]
这样的列表转换为地图%{1=>2, 3=>4}
的优雅高效方法是什么?我写了这个:
Enum.reduce([1,2,3,4],%{}, 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)
但这似乎并不优雅。这样做有更优雅,更清洁的方式吗?
答案 0 :(得分:18)
您可以避免额外拨打Enum.map/2
,并使用Map.new/2
直接构建新地图:
[1,2,3,4]
|> Enum.chunk_every(2)
|> Map.new(fn [k, v] -> {k, v} end)
更新:此答案的上一版本使用了chunk/2
但已被弃用,而不是chunk_every/2
。
答案 1 :(得分:14)
您可以使用Enum.chunk_every/2
:
[1, 2, 3, 4]
|> Enum.chunk_every(2)
|> Enum.map(fn [a, b] -> {a, b} end)
|> Map.new
答案 2 :(得分:8)
使用Enum.into
,它将转换函数作为第二个参数:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
答案 3 :(得分:6)
您可以使用尾递归来完成此任务:
defmodule Test do
def f(list, acc \\ [])
def f([x, y | xs], acc), do: f(xs, [{x, y} | acc])
def f(_, acc), do: Map.new(acc)
end
此解决方案比其他提出的解决方案更具时间效率。我编写了以下模块,以便能够对不同的解决方案进行基准测试:
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_every(2, 2, :discard)
|> Enum.map(fn [x, y] -> {x, y} end)
|> Map.new()
end
# Sheharyar's solution
def sheharyar(xs) do
xs
|> Enum.chunk_every(2, 2, :discard)
|> Map.new(fn [x, y] -> {x, y} end)
end
# Patrick's solution
def patrick(xs) do
xs
|> Enum.chunk_every(2, 2,:discard)
|> Enum.into(%{}, 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
# 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]
|> Stream.map(fn f -> timed(f, list, times) end)
|> Enum.sort(fn {_, x}, {_, y} -> x < y end)
end
end
因此小名单的bechmark如下:
iex(1)> Benchmark.test(0..100)
[alex: 10.1, sheharyar: 27.7, nietaki: 27.8, patrick: 29.2, chip: 63.5]
对于大型列表如下:
iex(2)> Benchmark.test(0..1_000_000)
[
alex: 197784.6,
patrick: 369645.9,
nietaki: 370870.2,
sheharyar: 372616.4,
chip: 794839.6
]
结果是平均运行时间(以微秒为单位),越少越好。如你所见,好的&#39;尾递归(Benchmark.alex/1
)在这种情况下做得更好。
我希望这有帮助:)