【问题标题】:A simple Erlang twister一个简单的 Erlang 扭曲器
【发布时间】:2017-06-20 13:26:39
【问题描述】:

我在玩 erlang 中的列表。我有以下格式的随机填充列表:

List=[{10,"English",id1},{20,"Maths",id2},{30,"Geo",id3},{20,"English",id4}]

格式为 [{Marks,Subject,Id}]。

我想从这个列表中列出一个只包含“英语”作为主题的列表,我做了如下操作

NewList=lists:filter(fun(A)->element(2,A)=="English",List)

这给了我

[{10,"English",id1},{20,"English",id4}]

这很好,但现在我想获取 NewList 中元组的 id,它具有更大的 Marks 值,例如,在这里,

id1id4 中,因为 id4 更大,我需要 Id4。

这里的问题是 List 是随机填充的列表,这意味着将来可能会出现所有 4 个条目,其主题仅为英语

任何人都可以提出一条出路。提前谢谢。

【问题讨论】:

    标签: erlang erlang-shell


    【解决方案1】:

    过滤列表后,你不能用lists:max/1 来获取最大标记的元组吗?

    lists:max(NewList)
    

    【讨论】:

    • lists:max/1 会给我最高分,但我想获得最高分的人的 ID
    • lists:max 会给你整个元组。我在整个列表上尝试了lists:max(没有过滤),它返回:{30,"Geo",id3}
    • 是的,你是对的,lists:max/1 采用元组的第一个元素并使用它来查找最大值。我尝试将元组的顺序更改为 [{subject,marks,id}] , 得到以数学为学科的元组为最大值。
    • @abhishekranjan:不,lists:max/1 不采用元组的第一个元素并使用它来查找最大值。见Erlang Term Comparisons。例如lists:sort([{1,b,2}, {1,a,2}, {1,d}]). 元组按大小排序,两个相同大小的元组逐个元素进行比较。
    【解决方案2】:

    如果我理解正确的话,那就行了:

    NewList = lists:filter(fun(A)->element(2,A)=="English" end,List).
    {_, _, MaxID} = lists:max(NewList).
    

    【讨论】:

    • 明白了,list:max/1 取元组中的第一个元素进行比较。
    【解决方案3】:

    我认为 Derek Brown 的 lists:foldl() 解决方案无法正常工作。 lists:foldl() 允许您在维护和操作单独变量的同时单步执行列表。在处理完最后一个元素后,lists:foldl() 返回单独的变量。在这种情况下,您可以使用单独的变量来更新得分最高的学生。

    您为lists:foldl() 提供了一个有趣的参数,它的参数是列表中的当前元素和您要操作的单独变量。 fun 的返回值是单独变量的新值。

    max_mark(Students, Subject) ->
        lists:foldl(
          fun({M,S,_Id}=Student, {Highest,_,_}) when S=:=Subject, M>Highest -> Student;
             (_Student, BestStudent) -> BestStudent
          end,
          {0, Subject, none},  %Starting value for the separate variable
          Students   %The list you want to step through
        ).
    

    在您的情况下,单独的变量将保存迄今为止得分最高的学生。

    在外壳中:

    50> c(my).                           
    {ok,my}
    
    51> Students = [{10,"English",id1},{20,"Maths",id2},{30,"Geo",id3},{30,"Maths",id1},{30,"English",id4},{20,"English",id3}].
    [{10,"English",id1},
     {20,"Maths",id2},
     {30,"Geo",id3},
     {30,"Maths",id1},
     {30,"English",id4},
     {20,"English",id3}]
    
    52> my:max_mark(Students, "English").                                                                                      
    {30,"English",id4}
    
    53> my:max_mark(Students, "Maths").                                                                                        
    {30,"Maths",id1}
    
    54> my:max_mark(Students, "Geo").                                                                                          
    {30,"Geo",id3}
    

    取得联系需要更多的工作。

    使用lists:foldl() 的优点是您只需遍历列表一次即可获取所需信息,而不是使用filter() 遍历列表一次,然后使用max() 遍历列表第二次。您可以想象,如果您有一个包含数百万个元素的列表,那么您应该尽可能少地遍历该列表。

    【讨论】:

    • 编辑了我的答案以说明具有相同标记的多个条目 - 好点。
    • @DerekBrown,操作员希望根据主题选择最高分,而不是总体最高分。连锁反应是您不能将列表中的第一个元素用作初始 Acc 值,因为它可能不是正确的主题。
    • 我知道,但是正如我在编辑的答案的第一段中提到的那样,OP 已经过滤了所需的主题。或者,可以使用原始列表并像您一样在代码中添加该检查,然后可以使用未定义原子的初始累加器或其他标志值,并添加一个有趣的子句来说明这种可能性(如果当前主题是所需的,acc 是标志值,返回一个新的 {N, [This]} 累加器(使用我的变量名)。
    • @DerekBrown,我知道,但是 OP 已经过滤了所需的主题 -- 你使用 foldl/foldr 的全部原因是你不必遍历名单不止一次!此外,您的示例实际上使用了不同的主题:a、b、c、d、e。
    • 明白了,就像我说的,如果不想先过滤,可以添加主题检查。 OP询问如何获得他们想要的答案,因为他们已经过滤了它,所以这样做了。我用过a,b,c等。作为虚拟值,因为它们与我展示的内容无关。这不是生产代码,而是显示不同的选项。 OP 可以根据需要使用它。 /me 洗了这个帖子的手
    【解决方案4】:

    请注意,这假设输入列表仅包含所需主题的元组,因为 OP 已经对其进行了过滤。或者,可以在此处添加该过滤器以避免该单独步骤。

    要获得每个元组的任意元素的最大值的元组(在这种情况下,标记可能不止一个具有相同的标记),而不用关心元组排序规则,可以做这样的事情(它确实使用第一个元素进行比较,如在这个问题中),只要列表包含至少一个元素。

    使用包含第一个列表条目的 Marks 值的元组以及该条目作为初始累加器。然后,从第二个元组开始,如果所讨论的输入元组的 Marks 等于当前最高值,则添加到累加器中的列表。如果当前输入元组的标记高于当前最高值,则将累加器中的列表替换为仅包含当前输入元组的新列表。否则,保持蓄电池原样。如果列表只包含一个条目,它将被返回,因为它是 foldl 调用中的初始累加器。

    find_max([{FirstMarks, _, _} = First | T]) ->
      lists:foldl(
        fun
          %% Current tuple from input list has marks higher than current highest in accumulator,
          %%   so reset the accumulator to this new value for marks and new list containing
          %%   just this input list tuple
          ({N, _, _} = This, {MaxN, _L}) when N > MaxN ->
            {N, [This]};
          %% Current tuple from input list has marks equal to current highest in accumulator,
          %%   so add this input list tuple to the accumulator's list
          ({N, _, _} = This, {N, L}) ->
            {N, [This | L]};
          %% Current tuple from input list has marks less than current highest in accumulator,
          %%   so don't change accumulator
          (_,  Acc) ->
            Acc
        end,
        %% Accumulator is tuple containing initial high value for marks, and list containing
        %%   containing the first element of the input list
        {FirstMarks, [First]}, T).
    
    1> tst_so:find_max([{30, a, a}]).
    {30,[{30,a,a}]}
    2> 
    2> tst_so:find_max([{30, a, a}, {20, b, b}, {40, c, c}, {10, d, d}, {40, e, e}]).
    {40,[{40,e,e},{40,c,c}]}
    3>
    

    【讨论】:

      【解决方案5】:
      1> List = [{10,"maths", "Joe"},{12,"english","Mark"},{10,"maths","Rebecca"},{15,"english","Janice"}].
      [{10,"maths","Joe"},
       {12,"english","Mark"},
       {10,"maths","Rebecca"},
       {15,"english","Janice"}]
      2> Best = fun(List,Subject) -> lists:foldl(fun({Mark,S,Id},{BestMark,_}) when Mark > BestMark, S == Subject -> {Mark,[Id]};                      
      2>                                            ({Mark,S,Id},{BestMark,Students}) when Mark == BestMark, S == Subject  -> {BestMark,[Id|Students]};
      2>                                            (_,Acc) -> Acc                                                                                           
      2>                                         end,{0,[]},List) end.                                                                                 
      #Fun<erl_eval.12.52032458>
      3> Best(List,"maths").                                                                                                                                 
      {10,["Rebecca","Joe"]}
      4> Best(List,"english").                                                                                                                               
      {15,["Janice"]}
      5> Best(List,"art").    
      {0,[]}
      6>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-27
        • 2011-04-06
        • 1970-01-01
        • 2011-01-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多