简体   繁体   中英

Haskell select elements in list

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.

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.

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)]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM