Erlang 查找元组列表中的所有元组
我目前正在攻读计算机科学硕士的第二学期,正在修分布式系统编程课程。因此,我们应该每周提交练习,其中也包括Erlang中的编码练习 由于这是本课程的第二周,我们才刚刚开始学习Erlang,这是第一个练习,我们应该在一个模块中实现6个函数。前5个功能我可以自己轻松完成,但第6个功能让我完全不知所措。对于这个函数,我们应该编写一个接受2个输入的函数:一个表示键值对的元组列表和一个包含要搜索的键的列表。然后,该函数应该在整个列表中搜索所有出现的这些键并返回它们 这是关于Erlang的第一个练习,目的是让我们熟悉语言的基本概念,这意味着我们应该通过使用递归而不是列表来解决这些任务:max 我能够为前一个任务实现一个工作函数,该任务只需在键值对元组列表中搜索一个键,并返回第一个结果。这项任务的实现似乎相当容易,但为了扩展这项任务,我尝试了太多不起作用的东西,以至于我甚至不知道下一步该尝试什么 目前我正在试验这种方法:Erlang 查找元组列表中的所有元组,erlang,tuples,key,key-value,Erlang,Tuples,Key,Key Value,我目前正在攻读计算机科学硕士的第二学期,正在修分布式系统编程课程。因此,我们应该每周提交练习,其中也包括Erlang中的编码练习 由于这是本课程的第二周,我们才刚刚开始学习Erlang,这是第一个练习,我们应该在一个模块中实现6个函数。前5个功能我可以自己轻松完成,但第6个功能让我完全不知所措。对于这个函数,我们应该编写一个接受2个输入的函数:一个表示键值对的元组列表和一个包含要搜索的键的列表。然后,该函数应该在整个列表中搜索所有出现的这些键并返回它们 这是关于Erlang的第一个练习,目的是让
find_all(Keys, Values) ->
AllFindings = [],
lists:foreach(
fun(Key) ->
lists:foreach(
fun(Value) ->
{X, Y} = Value,
case X == Key of
true -> AllFindings:append(Value);
false -> []
end
end,
Values
)
end,
Keys
),
AllFindings.
问题是,我需要做一些事情,比如将值附加到最初创建的列表中(这给了我一个错误:警告:无效的模块和/或函数名;此调用将始终失败
,而且我不确定它是否可能以我希望的方式工作,因为它需要变量AllFindings来更改其值)或者我需要一种方法来保存这些值以供以后使用,这样我可以在以后的某个时间点将它们一起输出,当我将所有的值一起输出时
但我真的不确定如何正确地实现这一点
我以前尝试实现这一点的方法是这样的,使用递归,但没有按照我预期的方式工作(此版本中的一些值输出仅用于“调试”,以查看在函数的什么状态下哪个变量具有哪个值):
如果有任何关于解决这个问题的建议,我会非常感激,无论是建议一些代码,还是让我参考相应的文献,因为对我来说,关于Erlang的文献/论坛似乎非常稀少,而且很难找到(特别是与Java或Python等流行语言相比)。到目前为止,我还在阅读“了解一些Erlang”但我没有遇到任何我认为它可能有助于解决这个问题的特定部分
编辑
我现在想出了这段代码:
find_all(Keys, Values) ->
while(Keys, Values).
while([], []) -> [];
while(Keys = [KeyHead | KeyTail], Values = [ValueHead | ValueTail]) ->
NumberOfKeys = length(Keys),
LengthOfValues = length(Values),
{K, V} = ValueHead,
erlang:display(Keys), erlang:display(Values),
case NumberOfKeys > 1 of
true -> case LengthOfValues > 1 of
true -> case K =:= KeyHead of
true -> [ValueHead | find_all(Keys, ValueTail)];
false -> [find_all(Keys, ValueTail)]
end;
false -> case K =:= KeyHead of
true -> [ValueHead];
false -> []
end
end;
false -> case LengthOfValues > 1 of
true -> case K =:= KeyHead of
true -> [ValueHead | find_all(Keys, ValueTail)];
false -> [find_all(Keys, ValueTail)]
end;
false -> case K =:= KeyHead of
true -> [ValueHead];
false -> []
end
end
end,
while(KeyTail, Values).
在我看来,它看起来很有希望,因为它的一个较小版本已经为这个函数调用返回了{d,3}。
warmup:find_all([d,x,c],{c,5},{z,7},{d,3},{a,1}])。
在使用erlang display()进行调试时
对于不同的值,我可以看到它在第一个键上循环了4次,并且将ValueTail
减少到最后一个值,然后移动到下一个键。但是我不明白为什么values
仍然只包含最后一个值{a,1}
,因为我认为递归返回到其调用的顶层,在那里列表仍然应该包含所有值?问题很长,所以为了清楚起见,这里有一个问题陈述:编写一个函数,它接受一个键值对元组列表和一个键值列表,并使用递归返回一个键值匹配的每对的列表s任意给定的键。根据此问题陈述,我们可以编写模块顶部-我们称之为keyfinder
-以导出find/2
函数:
find_all(Keys = [KeyHead | KeyTail], Values = [ValueHead | ValueTail]) ->
Tuples = [X || X = {KeyHead, Y} <- [ValueHead]],
Tuples,
ValueTail,
case Tuples /= [] of
true -> Tuples
end,
case ValueTail /= [] of
true -> find_all(Keys, ValueTail);
false ->
case KeyTail /= [] of
true -> find_all(KeyTail, Values);
false -> find_all(KeyTail, ValueTail)
end
end.
-module(keyfinder).
-export([find/2]).
现在,让我们考虑一些小的例子:
find([], _) -> []; % no pairs
find(_, []) -> []; % no keys
下一步,让我们考虑剩下的情况下,我们有对和键:给定n个键,我们必须搜索配对列表n次,并保持我们找到的每一个匹配的列表。为了跟踪匹配,我们可以使用一个累加器列表,开始为空。也许我们可以使用<代码>查找/ 3 < /代码>,其中额外的参数是累加器:
find(Pairs, Keys) ->
find(Pairs, Keys, []).
我们希望代码>查找/ 3 < /COD>递归调用自己来查找所有匹配,所以让我们考虑以下情况:代码>查找/ 3 < /COD>必须处理:
find(Pairs, Keys) ->
find(Pairs, Keys, Pairs, []).
这使得我们的递归函数find/4
取代了find/3
,并且我们将原始对列表原封不动地传递给每个find/4
调用
让我们让find/4
处理上述四种情况中的每一种:
%% We exhausted the list of keys, so return the results.
find(_, [], _, Results) -> Results;
%% We exhausted the list of pairs, so search for the rest of the keys.
find([], [_|Keys], OriginalPairs, Results) ->
find(OriginalPairs, Keys, OriginalPairs, Results);
%% Our pair matches our key, so add the pair to the accumulator and continue the search.
find([{Key,_}=Pair|Pairs], [Key|_]=Keys, OriginalPairs, Results) ->
find(Pairs, Keys, OriginalPairs, [Pair|Results]);
%% No match, continue the search.
find([_|Pairs], Keys, OriginalPairs, Results) ->
find(Pairs, Keys, OriginalPairs, Results).
最有趣的例子是第三个子句,其中我们在函数head中使用模式匹配将对中的键与键列表头部的键进行匹配
%% We exhausted the list of keys, so return the results.
find(_, [], _, Results) -> Results;
%% We exhausted the list of pairs, so search for the rest of the keys.
find([], [_|Keys], OriginalPairs, Results) ->
find(OriginalPairs, Keys, OriginalPairs, Results);
%% Our pair matches our key, so add the pair to the accumulator and continue the search.
find([{Key,_}=Pair|Pairs], [Key|_]=Keys, OriginalPairs, Results) ->
find(Pairs, Keys, OriginalPairs, [Pair|Results]);
%% No match, continue the search.
find([_|Pairs], Keys, OriginalPairs, Results) ->
find(Pairs, Keys, OriginalPairs, Results).
-module(keyfinder).
-export([find/2]).
find([], _) -> [];
find(_, []) -> [];
find(Pairs, Keys) ->
find(Pairs, Keys, Pairs, []).
find(_, [], _, Results) -> Results;
find([], [_|Keys], OriginalPairs, Results) ->
find(OriginalPairs, Keys, OriginalPairs, Results);
find([{Key,_}=Pair|Pairs], [Key|_]=Keys, OriginalPairs, Results) ->
find(Pairs, Keys, OriginalPairs, [Pair|Results]);
find([_|Pairs], Keys, OriginalPairs, Results) ->
find(Pairs, Keys, OriginalPairs, Results).
1> c(keyfinder).
c(keyfinder).
{ok,keyfinder}
2> keyfinder:find([],[]).
keyfinder:find([],[]).
[]
3> keyfinder:find([{a,1}],[]).
keyfinder:find([{a,1}],[]).
[]
4> keyfinder:find([],[a]).
keyfinder:find([],[a]).
[]
5> keyfinder:find([{a,1}],[a]).
keyfinder:find([{a,1}],[a]).
[{a,1}]
6> keyfinder:find([{a,1},{a,2}],[a]).
keyfinder:find([{a,1},{a,2}],[a]).
[{a,2},{a,1}]
7> keyfinder:find([{a,1},{a,2}],[a,b]).
keyfinder:find([{a,1},{a,2}],[a,b]).
[{a,2},{a,1}]
8> keyfinder:find([{a,1},{b,2}],[a,b]).
keyfinder:find([{a,1},{b,2}],[a,b]).
[{b,2},{a,1}]
9> keyfinder:find([{a,1},{b,2},{c,3}],[a,b]).
keyfinder:find([{a,1},{b,2},{c,3}],[a,b]).
[{b,2},{a,1}]
10> keyfinder:find([{a,1},{b,2},{c,3}],[a,b,c,d,e]).
keyfinder:find([{a,1},{b,2},{c,3}],[a,b,c,d,e]).
[{c,3},{b,2},{a,1}]
find(_, [], _, Results) -> lists:reverse(Results);
find([{Key,_}=Pair|Pairs], [Key|_]=Keys, OriginalPairs, Results) ->
find(Pairs, Keys, OriginalPairs, Results++[Pair]);