2017-06-19 22 views
1

Ich spielte mit den Listen in Erlang. Ich habe eine zufällig bevölkerten Liste in folgendem Format:Ein einfacher Erlang Twister

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

dies ist im Format [{Marks, Betreff, Id}].

Ich wollte eine Liste aus dieser Liste nur „Englisch“ als Thema, das ich

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

das gibt mir

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

das ist in Ordnung tat wie folgt

enthält, machen aber jetzt möchte ich die ID des Tupels innerhalb der NewList bekommen, die zum Beispiel den größeren Wert der Marken hat, hier

out o f id1 und id4 da id4 größer ist, brauche ich Id4.

Das Problem hierbei ist, dass die Liste zufällig bevölkerten Liste ist die, dass alle vier Einträge in Zukunft bedeutet Subjekt, das vorhanden sein können, ist nur auf Englisch verfügbar

Kann jemand einen Weg out.Thanks im Voraus vor.

Antwort

1

Nach dem Filtern der Liste, konnten Sie lists:max/1 nicht verwenden, um das Tupel mit maximalen Markierungen zu erhalten?

lists:max(NewList) 
+0

Listen: max/1 gibt mir die Höchstmarken, aber ich möchte die ID der Person maximal Markierungen erhalten –

+0

'Listen: max' werden Sie das ganze Tupel geben. Ich habe 'lists: max' auf den ganzen Listen versucht (ohne Filterung) und es gibt zurück:' {30, "Geo", id3} ' –

+0

ja du hattest Recht, Listen: max/1 nimmt das erste Element des Tupels und benutzt es, um das Maximum zu finden. Ich habe mit der geänderten Reihenfolge des Tupels als [{subject, marks, id}] versucht und habe das Tupel mit Mathe als Subjekt als Maximum bekommen. –

1

Wenn ich das richtig verstanden, dass das funktionieren würde:

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

Verstanden, Liste: max/1 nimmt das erste Element zum Vergleich in einem Tupel. –

0

Beachten Sie, dass dies setzt voraus, dass die Eingangsliste enthält nur Tupel gefiltert für den Gegenstand gewünscht, da die OP schon darauf. Alternativ könnte dieser Filter hier hinzugefügt werden, um diesen separaten Schritt zu vermeiden.

Um die Tupel mit dem Maximalwert eines beliebigen Elementes jedes einzelnen zu erhalten (Marken in diesem Fall, von denen mehrere mit denselben Marken sein könnten), könnten Sie etwas tun, ohne sich um Tupelordnungsregeln zu kümmern (die das erste Element zum Vergleich verwendet, wie in dieser Frage), solange die Liste mindestens ein Element enthält.

Verwendet ein Tupel, das den Wert der Marken für den ersten Listeneintrag und diesen Eintrag als anfänglichen Akkumulator enthält. Beginnen Sie dann, beginnend mit dem zweiten Tupel, der Liste im Akkumulator hinzuzufügen, wenn das betreffende Tupel Marks hat, die dem höchsten Wert entsprechen. Wenn das aktuelle Eingabetupel Markierungen über dem aktuellen Höchstwert hat, ersetzen Sie die Liste im Akkumulator durch eine neue Liste, die nur das aktuelle Eingabetupel enthält. Ansonsten, behalte Akku so wie er ist. Wenn die Liste nur einen Eintrag enthält, wird sie zurückgegeben, da sie der erste Akkumulator im foldl-Aufruf ist.

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

Ich glaube nicht, Derek lists:foldl() Lösung Brown korrekt funktionieren. lists:foldl() ermöglicht es Ihnen, durch eine Liste zu gehen, während Sie eine separate Variable pflegen und bearbeiten. Nachdem das letzte Element verarbeitet wurde, gibt lists:foldl() die separate Variable zurück. In diesem Fall können Sie die separate Variable verwenden, um den Schüler mit der höchsten Note zu aktualisieren.

Sie geben lists:foldl() mit einem Spaß, dessen Argumente das aktuelle Element in der Liste und die separate Variable sind, die Sie bearbeiten möchten.Der Rückgabewert des Spaßes ist der neue Wert für die separate Variable.

In Ihrem Fall wird die separate Variable den Schüler mit der höchsten Note bisher halten.

In der 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} 

Ersten Beziehungen werden noch einige Arbeit.

Der Vorteil lists:foldl() ist, dass Sie nur einmal die Liste durchlaufen müssen, um die gewünschten Informationen, eher zu bekommen, als die Liste einmal mit filter() und dann ein zweites Mal mit max() überquert. Sie können sich vorstellen, dass Sie, wenn Sie eine Liste mit Millionen von Elementen hätten, die Liste so oft wie möglich durchqueren müssten.

+0

Bearbeitete meine Antwort, um mehrere Einträge mit denselben Markierungen zu berücksichtigen - guter Punkt. –

+0

@DerekBrown, The op möchte die höchste Punktzahl basierend auf dem Thema auswählen - nicht die höchste Punktzahl insgesamt. Ein Anklopfen-Effekt ist, dass Sie das erste Element in der Liste nicht als den anfänglichen Acc-Wert verwenden können, da es möglicherweise nicht das richtige Thema ist. – 7stud

+0

Ich weiß, aber das OP filtert schon nach dem gewünschten Betreff, wie ich im ersten Absatz in meiner bearbeiteten Antwort erwähne. Alternativ dazu könnte man die rohe Liste verwenden und diesen Code in den Code einfügen, wie Sie es getan haben, und dann einen anfänglichen Akkumulator des Atoms undefiniert oder einen anderen Flag-Wert verwenden und eine fun-Klausel hinzufügen, die diese Möglichkeit berücksichtigt (wenn der aktuelle Subject ist der gewünschte, und der acc ist der Flag-Wert, Rückgabe eines neuen Akkumulators von {N, [This]} (unter Verwendung meiner Variablennamen)). –

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>