Home > Back-end >  Function that returns a list of strings, if the strings' paired number is smaller than the para
Function that returns a list of strings, if the strings' paired number is smaller than the para

Time:10-23

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)] == []

So far, I've tried:

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

Which doesn't work for fractional numbers and if the table contains more than one element that meets the criteria, I get a Non-exhaustive patterns error.

CodePudding user response:

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

There are a few problems with the current code:

  • The base case for the empty list (hence the non-exhaustive pattern error), whether it has been exhausted because of recursion or it was empty in the first place is missing.
  • you are adding y to the result regardless of the result of the condition. In the first case by concatenating and the second by adding it to the head of the result of the recursive call. y should only be added if its population is below the given threshold.
  • The signature provided by your function suggests it only uses integers but the input example have decimal numbers. I have changed the signature to accept decimal numbers.

CodePudding user response:

You're definitely on the right track. To be able to deal with fractional numbers, you should make your type signature a bit more general. Also, rather straightforward filtering tasks are arguably most elegantly expressed as list comprehensions:

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

Indeed:

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