2017-06-19 67 views
1

我在玩erlang中的列表。我有一個隨機填充的以下格式的列表:一個簡單的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中具有較大Mark值的元組的id,這裏,

out o f id1id4由於id4更大,我需要Id4。

這裏的問題是,名單是隨機填充的列表,這意味着,今後所有的4項可能存在,其主題是隻有英文

任何人可以事先提出一個方法out.Thanks。

回答

1

過濾完列表之後,難道你不能用lists:max/1來得到帶有最大標記的元組嗎?

lists:max(NewList) 
+0

名單:最大/ 1會給我最大的痕跡,但我想有最高分 –

+0

'名單的人的ID:max'會給你整個元組。我已經在整個列表上嘗試了'lists:max'(沒有過濾),並且它返回:'{30,「Geo」,id3}' –

+0

是的你是對的,列表:max/1接受元組的第一個元素,使用它來找到最大值。我嘗試將元組的順序改爲[{subject,marks,id}],並以數學作爲主題獲得元組作爲最大值。 –

1

如果我理解正確的話,將工作:

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

明白了,list:max/1將第一個元素作爲元組進行比較。 –

0

注意,這個假設輸入列表中只包含所需主題元組,作爲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> 
1

我不認爲德里克·布朗的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 
    ). 

在你的情況下,單獨的變量將持有迄今爲止最高分的學生。

在shell:

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()。你可以想象,如果你有一個包含數百萬個元素的列表,那麼你應該儘可能少地遍歷列表。

+0

編輯我的答案,考慮多個條目具有相同的標記 - 好點。 –

+0

@DerekBrown,該運動員希望根據主題選擇最高分數 - 而不是整體的最高分數。敲門效應是,您不能將列表中的第一個元素用作初始Acc值,因爲它可能不是正確的主題。 – 7stud

+0

我知道,但OP已經過濾了所需的主題,正如我在編輯答案的第一段中所提到的。或者,可以使用原始列表並在代碼中添加該檢查,就像您一樣,然後可以使用原子的初始累加器未定義或某個其他標誌值,並添加一個有趣的子句來解釋這種可能性(如果當前的主題是期望的,並且acc是標誌值,返回{N,[This]}的新累加器(使用我的變量名))。 –

0
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>