Reputation: 411
I've a problem with a function like this:
data City = City {Car :: String, Weight :: Int, Color :: String}
-I've a list of "City" and my function has to make a list of tuples, and each tuple is (Car, "sum of the weight"), therefore, if a the Car is equal, the weight has to be added, making something like this:
main> [(Porche,180),(Ferrari,400),(Opel,340)]
The car's can't be repeated on the output list, because their wheights must be added.
I was thinking of doing something like making a list with all the car types, and then filtering the weights and add them, making a list, but I just can't make it work.
Upvotes: 0
Views: 3205
Reputation: 26161
In terms of performance, perhaps it's best to use the Data.HashMap.Lazy
package for this job. Accordingly you may do it as follows;
import qualified Data.HashMap.Lazy as M
data City = City {car :: String, weight :: Int, color :: String}
ccw :: [City] -> [(String, Int)]
ccw [] = []
ccw (x:xs) = M.toList $ foldr addWeight (M.singleton (car x) (weight x)) xs
where
addWeight :: City -> M.HashMap String Int -> M.HashMap String Int
addWeight c r = case M.lookup (car c) r of
Nothing -> M.insert (car c) (weight c) r
Just x -> M.adjust (+ weight c) (car c) r
λ> ccw [City "Porsche" 180 "Black", City "Ferrari" 400 "Red", City "Opel" 340 "White", City "Porsche" 210 "Yellow"]
[("Opel",340),("Ferrari",400),("Porsche",390)]
Upvotes: 0
Reputation: 11208
I will guide you to the solution. It is better to understand how to arrive at the solution than the solution itself.
import Data.List
data City = City {car :: String, weight :: Int, color :: String} deriving (Show)
If color
has nothing to do with City
being equal you can convert the City
to a tuple. You can use map
to do that.
city2tup :: [City] -> [(String,Int)]
city2tup = map (\(City c w _) -> (c,w))
Now look at function sort
and groupBy
from Data.List
. Sorting and then grouping on the first element will collect together similar cars in a list. So you will have a list of list.
Now you just need to fold on each sublist and add corresponding weights.
collect :: [City] -> [(String,Int)]
collect = map (foldl1 collectWeight) . groupBy ((==) `on` fst) . sort . city2tup
You still need to define what collectWeight
is but that should be easy.
Upvotes: 4