I have a list of char and integer like [('1',1),('2',2),('3',3),('4',4),('5',5)] and want to turn the integers into the percentage each number count for the total such as [('1',7),('2',13),('3',20),('4',27),('5',33)]. I have tried a recursive function which takes a parameter as (c,i):rest and then divide the i by the total and then call the function with rest. But after every single loop, the total has changed. So is there any way I declare the total from start and use it over and over like other languages.
Add a comment
|
1 Answer
You need to calculate the total in advance - you can use something like
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
Note: it would be a good idea to collect the Integral-values associated to each character beforehand, this makes the output a bit more clear (in my opinion), but this would be an exercise for the astute reader.
To make this function more clear - I would also recommend introducing newtypes for Value and Percentage such that you never try to add values with percentages.
newtype Value a = V {extractV :: a}
newtype Percentage = P {percent :: Integer}
f :: Integral b => [(a,Value b)] -> [(a,Percentage)]
2 Comments
user2407038
Minor nitpick: you don't absolutely need to calculate the total in advance - you can compute the list result and the total in a single traversal of the input list, all thanks to the magic of laziness.
epsilonhalbe
@user2407038 I don't fully understand that - how can you use the sum-total without it being previously calculated and run this in a single traversal. do you mean that the computation of the percentage is deferred until the list is fully evaluated?