2016-10-10 57 views
1

我有一个char和整数列表,如[('1',1),('2',2),('3',3),('4',4),('5',5)],并且希望将整数转换为总数中的每个数字的百分比,例如[('1',7),('2',13),('3',20),('4',27),('5',33)]。我尝试了一个递归函数,它的参数为(c,i):rest,然后将i除以总数,然后用rest调用该函数。但在每一次循环之后,总数都发生了变化。那么是否有任何方法可以从头开始声明总体情况,并像其他语言一样反复使用它。Haskell - 递归函数中未修改的变量

回答

2

你需要预先计算总 - 您可以使用类似

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 

注:这将是收集相关的事先每个字符Integral - 值是个好主意,这使得输出有点更清楚(在我看来),但这将是一个聪明的读者的练习。

为了使这个功能更清晰 - 我也建议您推荐newtypes作为ValuePercentage,这样您就不会尝试用百分比添加数值。

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

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

小挑剔:你不一定需要提前计算总数* - 你可以计算列表结果和输入列表中的总数,这一切都归功于懒惰的魔力。 – user2407038

+0

@ user2407038我并不完全理解这一点 - 如何在不计算之前计算的总和的情况下使用总和,并在单次遍历中运行该总和。你的意思是百分比的计算被推迟到列表完全评估之后? – epsilonhalbe