SpecialSnowflake
SpecialSnowflake

Reputation: 995

Finding a tuple with two keys

For Example:

Db = [{pid1, {key1, {apple}}}, {pid1, {key2, {banana}}}, {pid1, {key3, {watermelon}}}, {pid2, {key1, {cucumber}}}, {pid2, {key2, {carrot}}}].

Being able to return the tuple where Pid = pid1, and Key = key1, which would be {pid1, {key1, {apple}}}. How would I go about doing this? Something similar to the BIF lists:keyfind/3.

Upvotes: 1

Views: 177

Answers (3)

Paul Guyot
Paul Guyot

Reputation: 6347

There are several ways to perform such lookups, and no best method. It is mostly a matter of style.

  • You can write a recursive function that will return as soon as the result is matched, as suggested by @Emil Vikström. The advantage is that you do not go through all the elements but the lookup will return as soon as a result is found, similar to what lists:keyfind/3 does. However, one could argue that if the list is long enough to justify such an optimization, another data structure could be more appropriate (like a sorted list or a tree).

  • You can use lists:filter/2 as suggested by @Pascal. This has the advantage over a recursive function to be based on a library function, which is always good for code maintenance.

  • You can use a filter within a list comprehension. This is similar than the lists:filter/2 approach, but a little shorter. Many see lists comprehension as more Erlang-like than using lists:map/2 and lists:filter/2, especially when the test is so short.

    [T || {Pid, {Key, _Value}} = T <- Db, Pid =:= MyPid, Key =:= MyKey].

    If key1 and pid1 are constants, you can even write:

    [T || {pid1, {key1, _Value}} = T <- Db].

Upvotes: 1

Emil Vikstr&#246;m
Emil Vikstr&#246;m

Reputation: 91983

If you want to break early when you find the value, you can implement it yourself using pattern matching:

pidkeyfind(_Pid, _Key, []) -> false;
pidkeyfind(Pid, Key, [Head = {Pid, {Key, _}} | _Tail]) -> Head;
pidkeyfind(Pid, Key, [_|Tail]) -> pidkeyfind(Pid, Key, Tail).

Upvotes: 0

Pascal
Pascal

Reputation: 14042

with lists:filter/2 it should work, here is an example of how to use it.

1> Db = [{pid1, {key1, {apple}}}, {pid1, {key2, {banana}}}, {pid1, {key3, {watermelon}}}, {pid2, {key1, {cucumber}}}, {pid2, {key2, {carrot}}}].
[{pid1,{key1,{apple}}},
 {pid1,{key2,{banana}}},
 {pid1,{key3,{watermelon}}},
 {pid2,{key1,{cucumber}}},
 {pid2,{key2,{carrot}}}]
2> Find = fun (K1,K2,L) -> lists:filter( fun({X,{Y,_}}) -> X =:= K1 andalso Y =:= K2 end,L) end.
#Fun<erl_eval.18.82930912>
3> Find(pid1,key1,Db).
[{pid1,{key1,{apple}}}]

Upvotes: 1

Related Questions