1

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.

1 Answer 1

2

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)]
Sign up to request clarification or add additional context in comments.

2 Comments

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.
@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?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.