2016-10-10 5 views
1

Ich habe eine Liste von Zeichen und Ganzzahl wie [('1',1),('2',2),('3',3),('4',4),('5',5)] und möchte die Ganzzahlen in den Prozentsatz jeder Zahl für die Gesamtzahl wie [('1',7),('2',13),('3',20),('4',27),('5',33)] drehen. Ich habe eine rekursive Funktion versucht, die einen Parameter wie (c,i):rest nimmt und dann die i durch den Gesamtbetrag teilt und dann die Funktion mit rest aufruft. Aber nach jeder einzelnen Schleife hat sich die Gesamtsumme geändert. Also gibt es irgendeine Weise, die ich die Summe von Anfang an deklariere und es wie andere Sprachen immer wieder benutze.Haskell - unmodifizierte Variable in einer rekursiven Funktion

Antwort

2

Sie müssen die gesamten im Voraus berechnen - Sie so etwas wie

f :: Integral b => [(a,b)] -> [(a,b)] 
f lst = let total = sum $ map snd list 
     in map (\(x,y) -> (x,(100 * y)`div` total)) lst 

verwenden können Hinweis: es wäre eine gute Idee, die Integral -Werten jedes Zeichen vorher zugeordnet zu sammeln, macht dies die Ausgabe einer etwas klarer (meiner Meinung nach), aber das wäre eine Übung für den scharfsinnigen Leser.

Um diese Funktion deutlicher zu machen - ich würde auch empfehlen, newtypes für Value und Percentage einzuführen, so dass Sie nie versuchen, Werte mit Prozentsätzen hinzuzufügen.

newtype Value a = V {extractV :: a} 
newtype Percentage = P {percent :: Integer} 

f :: Integral b => [(a,Value b)] -> [(a,Percentage)] 
+0

Minor nitpick: Sie müssen nicht unbedingt brauchen die Gesamt * im Voraus zu berechnen * - die Liste Ergebnis und die Summe in einem einzigen Durchlauf der Eingabeliste berechnen kann, alles dank der Magie der Faulheit. – user2407038

+0

@ user2407038 Das verstehe ich nicht ganz - wie kann man die Summe verwenden, ohne dass sie vorher berechnet wurde und dies in einer einzigen Traversierung ausführen. meinen Sie, dass die Berechnung des Prozentsatzes aufgeschoben wird, bis die Liste vollständig ausgewertet ist? – epsilonhalbe

Verwandte Themen