import Data.Char
type Games = (String, String, Int)
test :: [Games]
test =
[
("Minecraft","mojang",100),
("GTA V","rockstar",500),
("Portal","valve",200),
("GTA IV","rockstar",100)
]
-- give the total number of sales for a studio
studioSales :: String -> [Games] -> [Int]
studioSales studioName [] = []
studioSales studioName ((name,studio,quantitySold):xs)
| studioName == studio = quantitySold: studioSales studioName xs
| otherwise = studioSales studioName xs
当调用函数“studioSales”rockstar“test”时,返回的值为“[500,100]”。
如何调整此值,以便在调用“studioSales”rockstar“test”时,返回的值为“[600]”,其中两个Int值相加。
另外,我如何将所有销售额加起来?所以一个函数会返回所有加起来的整数吗?
答案 0 :(得分:3)
第一次通过我:
fst3 (x, _, _) = x
snd3 (_, y, _) = y
thrd (_, _, z) = z
studioSales studio = sum . map thrd . filter ((studio ==) . snd3)
我认为你的代码可以通过一些更好的命名来实现,不过
data Game = Game { title :: String, studio :: String, cntSold :: Int }
type Games = [Game]
test =
[ Game "Minecraft" "mojang" 100
, Game "GTA V" "rockstar" 500
, Game "Portal" "valve" 200
, Game "GTA IV" "rockstar" 100
]
sumSold :: Games -> Int
sumSold = sum . map cntSold
singleStudio :: String -> Games -> Games
singleStudio s = filter ((s ==) . studio)
sumSoldByStudio = (sumSold .) . singleStudio
-- or: sumSoldByStudio s = sumSold . singleStudio s
顺便说一句,如果你真的想要一个[Int]
(Int
s列表)而不是一个Int
,你可以使用(:[])
或return
将单个值放入列表(第二个由于列表monad)。像这样:
sumSold :: Games -> [Int]
sumSold = return . sum . map cntSold
答案 1 :(得分:2)
你可以做的是对函数的输出进行折叠以总结结果,如下所示:
foldl (+) 0 $ studioSales "rockstar" test
使用上述想法,我们可以通过添加您当前返回的Int
列表的元素来更改函数本身以返回单个Int
值:
sumByStudio:: String -> [Games] -> Int
sumByStudio studioName [] = 0
sumByStudio studioName xs = foldl (\x acc -> if fst acc == studioName then x + snd acc else x) 0 $ map getStudioAndCount xs
getStudioAndCount :: Games -> (String, Int)
getStudioAndCount (x,y,z) = (y,z)
注意使用辅助函数来获取实际上重要的2个元素的元组。但这看起来仍然很难看,而且可以更简洁。
现在我们已经有了折叠的基本思路来得到总和,我们改变它,首先使用filter
来获取所选工作室的所有记录,然后使用foldr
:
sumByStudio:: String -> [Games] -> Int
sumByStudio3 studioName [] = 0
sumByStudio3 studioName xs = foldr(\(_,_,z) acc -> z + acc) 0 $ filter (\(_,y,_) -> y == studioName) xs
请注意,在lambda中使用模式匹配消除了对我们在foldl
示例中使用的辅助函数的需要。
最后,由于以上所有内容基本上都返回一个表示总和的值,因此将返回类型设为Int
而不是[Int]
可能是个好主意。但是,如果由于某种原因需要返回[Int]
,可以像这样修改函数:
sumByStudio3 studioName xs = flip (:) [] $ foldr(\(_,_,z) acc -> z + acc) 0 $ filter (\(_,y,_) -> y == studioName) xs
要回答第二个问题,关于总结所有销售,你可以这样做:
sumAll :: [Games] -> Int
sumAll [] = 0
sumAll xs = foldr(\(_,_,z) acc -> z + acc) 0 xs