根据分数拆分学生名单 - haskell

Split list of student according to their mark - haskell

有一个学生列表

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

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

我需要这样拆分它[(mark,[students with this mark])]

我做了这样的东西:

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

但它工作不正确。也许有人知道怎么做..

如果可以使用标准工具,请不要手动递归。您可以通过排序和分组来做到这一点,但 IMO 更可取的是使用类型来表示您正在构建一个 associative 结果,即从标记到学生的映射。

import qualified Data.Map as Map

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

(如果你想要最后一个列表,就用Map.toList。)

如果您将 Student 视为元组,则您的函数具有此类型:splitToGroups :: [(Mark,String)] -> [(Mark, [String])]。 所以你需要一个类型为 [(a,b)] -> [(a,[b])].

的函数

使用Hoogle:search results

我得到以下功能:

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

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

它们应该可以解决您的问题,请记住导入 link 中列出的模块以使它们正常工作。您应该首先创建一个从 Student -> (Mark, String) 映射的函数。