Home > OS >  Split list of student according to their mark - haskell
Split list of student according to their mark - haskell

Time:12-10

There is a list of students where

data Student = Student {
   name :: String,
   mark :: Mark
} deriving Show

data Mark = F|E|D|C|B|A deriving (Show, Eq, Ord)

I need to split it like that [(mark,[students with this mark])]

I made something like this:

splitToGroups :: [Student] -> [(Mark, [String])]    
splitToGroups [] = []
splitToGroups students = foldr funct [] students where
    funct student [] = [(mark student,[name student])]
    funct student ((x,xs):xss) | mark student == x = ((x,(name student):xs):xss)
                               | otherwise = (mark student,[name student]):(x,xs):xss

but it works incorectly. Maybe someone knows how it could be done..

CodePudding user response:

Don't manually recurse if you can use standard tools. You can do this with sorting and grouping, but IMO preferrable is to use the types to express that you're building an associative result, i.e. a map from marks to students.

import qualified Data.Map as Map

splitToGroups :: [Student] -> Map.Map Mark [String]
splitToGroups students = Map.fromListWith (<>)
     [ (sMark, [sName])
     | Student sName sMark <- students ]

(If you want a list in the end, just use Map.toList.)

CodePudding user response:

If you view Student as a tupple, your function has this type: splitToGroups :: [(Mark,String)] -> [(Mark, [String])]. So you need a function with type: [(a,b)] -> [(a,[b])].

Using Hoogle: search results

I get the following functions:

groupSort :: Ord k => [(k, v)] -> [(k, [v])]

collectSndByFst :: Ord a => [(a, b)] -> [(a, [b])]

They should solve your problem, remember to import the modules listed in the link to make them work. You should make a funtion that maps from Student -> (Mark, String) first.

  • Related