【问题标题】:Assigning rank to a list of tuples in haskell为haskell中的元组列表分配排名
【发布时间】:2014-01-04 00:23:30
【问题描述】:

如何为 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。更一般地说,对于特定等级范围 [i..j],任意 n 数量的并列都将获得相同等级的 sum [i..j] / n。

注意:我今天刚开始学习 Haskell(来自 Python 和 Java),所以我更愿意提供有用的提示而不是揭示答​​案。足以将我推向正确的解决方案。谢谢!

编辑/第 2 部分问题:好的,感谢 jamshidh、chunsof50 和 leftaroundabout,我想出了

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 ]

我对 sortStudentsprerankStudents 比较满意,但是 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   

【问题讨论】:

    标签: haskell tuples rank


    【解决方案1】:

    这里有一些你会发现有用的功能......

    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
    (==)
    

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

    这足以让你在不给出完整答案的情况下继续前进。

    【讨论】:

      【解决方案2】:

      您要求的提示和技巧,所以这里先附上提示:

      1. 使用hoogle 了解函数。
      2. 使用类型签名并注意它们。
      3. 通过以纯函数方式做事,您将从学习 haskell 中学到更多知识,因此除了最终管道外,请避免使用 IO monad,否则您最终会像以前一样编写代码。
      4. 递归是你的扳手,但高阶函数是你的重型机器。
      5. 编写大量的小函数来做一些简单的事情,而不是一个解决问题的大函数

      提示

      • zipzipWith - 组合列表。你会在某个时候想要无限列表[1..]
      • groupBy。当我们在这个领域时,有必要在某个时候查看函数 on,但在这种情况下,类型签名通常没有太大帮助,您希望查看示例。
      • sumlengthmap。您将不得不通过map 发挥创意; map 是一个基本的列表处理函数。使用类型找出您可能使用的fst.sndsnd.fstfst.fstsnd.snd
      • map 更多,最后你需要concat

      您最终可能会定义额外的函数,或者最终采用非常不同的方式,但学习这些将培养您的 Haskell 技能。

      【讨论】:

        【解决方案3】:

        如果确实列表 os 已经排序(if not, trivial to usesortBy 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" 共享一个列表。

        然后,对于这些列表中的每一个,您平均排名。这可以很好地写成带有模式匹配的列表推导式,这是你可以作为练习做的一件好事。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-16
          • 1970-01-01
          • 1970-01-01
          • 2012-10-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多