how to get value from keyword list which key is integer?

Viewed 142

The list is like [{0,10},{2,20}]. I have get value 10 when provided by key as 0.

I haven't find the suitable function in Enum, List, Keyword module, and have to use erlang module proplists to solve the problem. Is it necessary?

inventory_position_list = [{0,10},{2,20}]
x = :proplists.get_value(0,inventory_position_list)
4 Answers

I believe List.keyfind/4 or List.keyfind!/3 are what you are looking for:

iex> List.keyfind!([{0,10},{2,20}], 2, 0)
{2, 20}

This returns the whole matching tuple though, so you'd need to pattern-match on the return:

{_, value} = List.keyfind!(list, key, 0)

Since everyone is posting suboptimal answers (except for sabiwara), I'll join in.

Enum.find_value/3:

Enum.find_value([{0, 10}, {2, 20}], fn
  {0, value} -> value
  _ -> nil
end)

Manual recursion:

def find_keyword_value([], _key), do: nil
def find_keyword_value([{key, value} | _], key), do: value
def find_keyword_value([_ | rest], key), do: find_keyword_value(rest, key)

Both of these return the value, not the tuple.


By the way, I benchmarked the results of the answers here, and on my machine at least in order of speed they are:

Name                         ips        average  deviation         median         99th %
keyfind                   3.14 M      318.53 ns  ±5017.22%         290 ns         319 ns
find_keyword_value        2.70 M      370.27 ns   ±100.46%         364 ns         386 ns
find_value                1.23 M      811.32 ns  ±1335.56%         752 ns        1059 ns
reduce_while              1.01 M      990.33 ns  ±1677.02%         893 ns        1234 ns
find                      0.77 M     1298.85 ns  ±1159.26%        1137 ns        2749 ns

Comparison:
keyfind                   3.14 M
find_keyword_value        2.70 M - 1.16x slower +51.74 ns
find_value                1.23 M - 2.55x slower +492.80 ns
reduce_while              1.01 M - 3.11x slower +671.81 ns
find                      0.77 M - 4.08x slower +980.32 ns

Operating System: macOS
CPU Information: Intel(R) Core(TM) i5-6600 CPU @ 3.30GHz
Number of Available Cores: 4
Available memory: 24 GB
Elixir 1.13.3
Erlang 25.0

As alternative to everything posted above, Enum.find/3 can also be used:

{_key, value} = Enum.find(inventory_position_list, nil, fn 
  {key, _value} -> key == 0 
end)

Just for the sake of completeness, I’d post the solution using a sledgehammer aka Enum.reduce_while/3 which works for me without the necessity to memorize all the helper functions.

Enum.reduce_while([{0, 10}, {2, 20}], nil, fn
  {0, value}, nil -> {:halt, value}
  _ , nil -> {:cont, nil}
end)
#⇒ 10
Related