例如:
Db = [{pid1, {key1, {apple}}}, {pid1, {key2, {banana}}}, {pid1, {key3, {watermelon}}}, {pid2, {key1, {cucumber}}}, {pid2, {key2, {carrot}}}].
能够返回 Pid = pid1 和 Key = key1 的元组,即 {pid1, {key1, {apple}}}。我该怎么做呢?类似于 BIF 列表的东西:keyfind/3。
使用 lists:filter/2 它应该可以工作,这是一个如何使用它的示例。
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}}}]
有几种方法可以执行此类查找,但没有最佳方法。这主要是风格问题。
正如@Emil Vikström所建议的那样,您可以编写一个递归函数,一旦结果匹配就会返回。优点是您不会遍历所有元素,但查找将在找到结果后立即返回,类似于执行的操作。但是,有人可能会争辩说,如果列表足够长以证明这种优化是合理的,那么另一种数据结构可能更合适(如排序列表或树)。lists:keyfind/3
您可以lists:filter/2
按照@Pascal 的建议使用。与基于库函数的递归函数相比,这具有优势,这总是有利于代码维护。
您可以在列表理解中使用过滤器。这与lists:filter/2
方法相似,但要短一些。lists:map/2
许多人认为列表理解比使用and更像 Erlang lists:filter/2
,尤其是在测试很短的时候。
[T || {Pid, {Key, _Value}} = T <- Db, Pid =:= MyPid, Key =:= MyKey].
如果 key1 和 pid1 是常量,你甚至可以这样写:
[T || {pid1, {key1, _Value}} = T <- Db].
如果您想在找到值时尽早中断,可以使用模式匹配自己实现:
pidkeyfind(_Pid, _Key, []) -> false;
pidkeyfind(Pid, Key, [Head = {Pid, {Key, _}} | _Tail]) -> Head;
pidkeyfind(Pid, Key, [_|Tail]) -> pidkeyfind(Pid, Key, Tail).