在Elixir列表中查找与最小长度列表关联的密钥的有效方法是什么。我们说我有:
const getKeyOfObject = (key) => markers.map(item =>
item.coords[key]).join('')
getKeyOfObject('lat') // 14.5858544
我知道我能做到:
z = %{a: [1, 2, 3], b: [4, 5], c: [6, 7, 8, 9]}
会给我:
Enum.map z, fn {k, v} -> length(v) end
但我真正需要的只是答案,即与最小值2相关的关键,当然是:b。
我将在动态地图列表中大约每秒运行一次,所以我希望它尽可能高效。
答案 0 :(得分:3)
除非绝对必要,否则我更喜欢简单而不是性能,所以如果性能不那么令我担心,我会如何做到这一点:
map
|> Enum.min_by(fn {_k, v} -> length(v) end)
|> elem(0)
通过@Dogbert添加基准测试显示,平均速度慢了约1.5倍。在我的机器上90μs/迭代。这仍然是每秒运行它的充足空间。
答案 1 :(得分:2)
如果您正在寻找速度,:maps.fold
通常会比Enum.reduce
快一点。这是一个比@ mudasobwa实施快〜10%的实现:
:maps.fold(
fn k, v, {_, min} = acc ->
l = length(v)
if min == 0 || l < min, do: {k, l}, else: acc
end,
{nil, 0},
map
)
|> elem(0)
基准代码:
map = for(key <- 1..1000, into: %{}, do: {key, Enum.random([[1, 2, 3], [4, 5], [6, 7, 8, 9]])})
Benchee.run(%{
"mudasobwa" => fn ->
Enum.reduce(map, {nil, 0}, fn
{k, v}, {_, len} when len == 0 or len > length(v) -> {k, length(v)}
_, acc -> acc
end)
|> elem(0)
end,
"dogbert" => fn ->
:maps.fold(
fn k, v, {_, min} = acc ->
l = length(v)
if min == 0 || l < min, do: {k, l}, else: acc
end,
{nil, 0},
map
)
|> elem(0)
end
})
输出:
Name ips average deviation median 99th %
dogbert 12.36 K 80.90 μs ±25.05% 73 μs 146.20 μs
mudasobwa 11.14 K 89.81 μs ±34.32% 80 μs 185 μs
Comparison:
dogbert 12.36 K
mudasobwa 11.14 K - 1.11x slower
答案 2 :(得分:1)
在Elixir中执行任何操作的最有效方法是Enum.reduce/3
:
Enum.reduce(z, {nil, 0}, fn
{k, v}, {_, len} when len == 0 or len > length(v) -> {k, length(v)}
_, acc -> acc
end)
#⇒ {:b, 2}
要仅获取:b
,模式匹配结果:
{key, _} = ⇑the above⇑
或(更糟)管道|> Tuple.to_list() |> List.first
。
这里我们更新累加器如果:
答案 3 :(得分:0)
对于任何想重复@ Dogbert基准测试的人,包括Patrick Oscity的回答:
map = for(key <- 1..1000, into: %{}, do: {key, Enum.random([[1, 2, 3], [4, 5], [6, 7, 8, 9]])})
Benchee.run(%{
"mudasobwa" => fn ->
Enum.reduce(map, {nil, 0}, fn
{k, v}, {_, len} when len == 0 or len > length(v) -> {k, length(v)}
_, acc -> acc
end)
|> elem(0)
end,
"dogbert" => fn ->
:maps.fold(
fn k, v, {_, min} = acc ->
l = length(v)
if min == 0 || l < min, do: {k, l}, else: acc
end,
{nil, 0},
map
)
|> elem(0)
end,
"oscity" => fn ->
map
|> Enum.min_by(fn {_k, v} -> length(v) end)
|> elem(0)
end
})
我在Nvidia TX2(64位ARM)上的结果:
Name ips average deviation median 99th %
oscity 252.78 3.96 ms ±3.01% 3.92 ms 4.38 ms
mudasobwa 80.66 12.40 ms ±1.61% 12.37 ms 13.15 ms
dogbert 32.90 30.39 ms ±0.90% 30.32 ms 31.27 ms
Benchee代码在这里:
https://hex.pm/packages/benchee
即添加
{:benchee, "~> 0.12.1"}
在mix.exs的deps下。