Erlang 查找元组列表中的所有元组

Erlang 查找元组列表中的所有元组,erlang,tuples,key,key-value,Erlang,Tuples,Key,Key Value,我目前正在攻读计算机科学硕士的第二学期,正在修分布式系统编程课程。因此,我们应该每周提交练习,其中也包括Erlang中的编码练习 由于这是本课程的第二周,我们才刚刚开始学习Erlang,这是第一个练习,我们应该在一个模块中实现6个函数。前5个功能我可以自己轻松完成,但第6个功能让我完全不知所措。对于这个函数,我们应该编写一个接受2个输入的函数:一个表示键值对的元组列表和一个包含要搜索的键的列表。然后,该函数应该在整个列表中搜索所有出现的这些键并返回它们 这是关于Erlang的第一个练习,目的是让

我目前正在攻读计算机科学硕士的第二学期,正在修分布式系统编程课程。因此,我们应该每周提交练习,其中也包括Erlang中的编码练习

由于这是本课程的第二周,我们才刚刚开始学习Erlang,这是第一个练习,我们应该在一个模块中实现6个函数。前5个功能我可以自己轻松完成,但第6个功能让我完全不知所措。对于这个函数,我们应该编写一个接受2个输入的函数:一个表示键值对的元组列表和一个包含要搜索的键的列表。然后,该函数应该在整个列表中搜索所有出现的这些键并返回它们

这是关于Erlang的第一个练习,目的是让我们熟悉语言的基本概念,这意味着我们应该通过使用递归而不是列表来解决这些任务:max

我能够为前一个任务实现一个工作函数,该任务只需在键值对元组列表中搜索一个键,并返回第一个结果。这项任务的实现似乎相当容易,但为了扩展这项任务,我尝试了太多不起作用的东西,以至于我甚至不知道下一步该尝试什么

目前我正在试验这种方法:

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>必须处理:

  • pairs列表头部的键与keys列表头部的键匹配:将该对添加到累加器中,并递归地在其余对中搜索相同的键
  • pairs列表头部的键与keys列表头部的键不匹配:递归地在其余对中搜索相同的键
  • 密钥列表为空:返回累加器
  • pairs列表是空的:通过遍历pairs列表,我们的递归最终到达这里;递归地在整个pairs列表中搜索剩余的每个键
  • 在上面的最后一个例子中,我们的递归可能会导致这样一种情况:我们检查了所有对,从而清空了对列表,但仍有更多的键需要搜索;这意味着我们需要将原始对列表保留在某个位置,以用下一个键重新开始搜索。一种方法是添加另一个参数,即原始lis成对t:

    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]);