将等级分配给haskell中的元组列表

时间:2014-01-04 00:23:31

标签: haskell tuples rank

如何将排名分配给Haskell中的元组列表(考虑到关系)?理想情况下,想要一个给出元组列表的函数,会返回一个带有等级的元组列表。

示例输入(假设基于每个元组的snd以升序排序):

results1 = [("a",12),("b",56),("c",61),("d",73),("e",75),("f",75),("g",81),("h",82),("i",91),("j",97)]

示例输出:

[("a",1),("b",2),("c",3),("d",4),("e",5.5),("f",5.5),("g",7),("h",8),("i",9),("j",10)]

注意“e”和“f”并列,所以他们将他们的等级(5和6)加在一起并除以2.更一般地说,对于特定等级范围的任何n量的关系[i..j]将全部收到相同的总和[i..j] / n。

注意:我刚刚开始学习Haskell(来自Python和Java),所以我更愿意提供有用的提示而不是揭示答​​案。足以让我找到合适的解决方案。谢谢!

编辑/第2部分问题:好的,所以感谢jamshidh,chunksof50,以及左撇子我想出了

sortStudents xs = sortBy (compare `on` snd) xs

prerankStudents xs = groupBy ((==) `on` (snd.fst)) (zip (sortStudents xs) [1..])

rankStudents xs = concat [ [if length ys > 1 then (a, fromIntegral (sum (map snd ys)) / fromIntegral (length ys)) else (a,fromIntegral c) | ((a,b),c) <- ys] | ys <- (prerankStudents . sortStudents) xs ]

我对 sortStudents prerankStudents 感到满意,但是 rankStudents 感觉有点像我正在再次编写python(列表理解)虽然我不确定在这种情况下它是好还是坏。我尝试用case..of递归地实现 rankStudents ,但是在我的头脑中平滑错误。这是代码,如果有人要向我解释为什么它不起作用。

rankStudents xs = let ss = prerankStudents xs
              rankStudents' ys = case ys of [] -> []
                            [((a,b),c)] -> [(a,c)]
                            (((a1,b1),c1):zs) -> [((fst.fst) tup, fromIntegral (sum (map snd ys)) / fromIntegral (length ys)) | tup <- ys]              
                            y:ys -> rankStudents' y ++ rankStudents' ys
              in rankStudents' ss   

3 个答案:

答案 0 :(得分:4)

以下是一些有用的功能....

Data.List.groupBy
Data.List.sortBy --you won't actually need this if you assume the input is ordered, but I threw it in anyway
Data.Function.on
(==)

您可以按第二项对数据进行分组,然后使用递归输出值,增加每个项目的排名....如果组中的项目数大于1,则只增加此值,然后输出这些值的平均值取决于组中的排名。

这足以让你无需给出完整的答案。

答案 1 :(得分:3)

您要求的提示和提示,所以首先请先提示:

  1. 使用hoogle查找有关功能的信息。
  2. 使用类型签名并注意它们。
  3. 通过以纯粹的功能方式做事,你将从学习haskell中学到更多东西,所以除了最后的管道之外,要避免使用IO monad,否则你最终会像以前那样写作。
  4. 递归是你的扳手,但更高阶的功能是你的重型机械。
  5. 编写许多简单的小函数,而不是一个解决的大函数
  6. 提示

    • zipzipWith - 合并列表。在某些时候你会想要无限列表[1..]
    • groupBy。我们在这个区域的某个时刻值得查看函数on,但是那个不常见的类型签名没有多大帮助,你想看看这些例子。
    • sumlengthmap。你将不得不通过map获得创意; map是一个基本的列表处理函数。使用类型来确定您可以使用fst.sndsnd.fstfst.fstsnd.snd
    • map更多,最后您需要concat

    你最终可能会定义其他功能,或者最终以一种非常不同的方式进行,但了解这些功能将构建你的Haskell技能。

答案 2 :(得分:2)

如果确实列表已经排序(if not, trivial to use sortBy comparing snd),那么这或多或少用简单的枚举替换snd字段。首先进行枚举!这在Haskell中非常简单:zip results1 [1..]生成

[(("a",12),1),(("b",56),2),(("c",61),3),(("d",73),4),(("e",75),5),(("f",75),6),(("g",81),7),(("h",82),8),(("i",91),9),(("j",97),10)]

剩下要做的事情主要是均衡重复。我首先分组那些:groupBy ((==)`on`(snd.snd))给出

[[(("a",12),1)],[(("b",56),2)],[(("c",61),3)],[(("d",73),4)],[(("e",75),5),(("f",75),6)],[(("g",81),7)],[(("h",82),8)],[(("i",91),9)],[(("j",97),10)]]

请注意除"e""f"共享列表外,所有元素现在都是单个列表中的所有元素。

然后,对于每个列表,您平均排名。这可以很好地写成一个列表理解与模式匹配,这是一个你可以作为一个练习做的好事。