函数 returns 一个字符串列表,如果字符串的配对数小于参数的数字

Function that returns a list of strings, if the strings' paired number is smaller than the parameter's number

Implement the populationBelow :: Int -> [(String, Int)] -> [String] function, that returns the names of the countries from the given table whose population (million people) is less than the number given in the parameter.

For example:

populationBelow 10 [ ("Hungary", 9.773),
("Japan", 126.8),
("Iceland", 0.3604),
("United States", 327.2),
("Mongolia", 3.076)
] == ["Hungary", "Iceland", "Mongolia"]

populationBelow 0 [ ("Hungary", 9.773),
("Japan", 126.8),
("Iceland", 0.3604),
("United States", 327.2),
("Mongolia", 3.076)] == []

到目前为止,我已经尝试过:

populationBelow x ((y, z):ys) | z < x = [y] ++ populationBelow x (ys)
                              | otherwise = (y) : populationBelow x (ys)

这不适用于小数,如果 table 包含多个符合条件的元素,我会收到 Non-exhaustive patterns 错误。

populationBelow :: RealFrac a => a -> [(String, a)] -> [String]
populationBelow _ [] = []
populationBelow x ((y, z):ys)
  | z < x = y : populationBelow x ys
  | otherwise = populationBelow x ys

当前代码存在一些问题:

  • 缺少空列表的基本情况(因此出现非穷举模式错误),它是因为递归而穷尽还是一开始就是空的。
  • 无论条件结果如何,您都将 y 添加到结果中。在第一种情况下通过连接,在第二种情况下通过将其添加到递归调用结果的头部。 y 仅当其人口低于给定阈值时才应添加。
  • 你的函数提供的签名表明它只使用整数,但输入示例有十进制数。我已将签名更改为接受十进制数字。

您绝对是在正确的轨道上。为了能够处理小数,你应该让你的类型签名更通用一点。此外,相当简单的过滤任务可以说是最优雅地表达为列表理解:

populationBelow :: Ord b => b -> [(a, b)] -> [a]
populationBelow k xs = [x | (x, n) <- xs, n < k]

确实:

> populationBelow 10 [("Hungary", 9.773), ("Japan", 126.8), ("Iceland", 0.3604), ("United States", 327.2), ("Mongolia", 3.076)]
["Hungary","Iceland","Mongolia"]