I am working on a assignment that checks if there is only a single element that satisfies a given condition, I've thought about passing map to get a list of Boolean values and then counting if it has value 1 if it does I return True if not then I return False.
single :: (a -> Bool) -> [a] -> Bool
single p [] = False
single p a = map p a
let c = single p a
single count True c = if k == 1
then True
else False
Which I have count that is:
count :: (Num a, Eq b) => b -> [b] -> a
count _ [] = 0
count x list = sum $ map (const 1) $ filter (== x) list
CodePudding user response:
Your solution contains some errors. For example the second parameter of single is a list, so single count True c
makes no sense. You can work with:
single :: (a -> Bool) -> [a] -> Bool
single p a = count True (map p a) == 1
but is not very efficient. filter p a
will produce a list with the same length as filter (== True) (map p a)
, and does not require first mapping and then filtering. Furthermore by counting the number of items that satisfy the condition, you will enumerate over the entire list, even if you already found two items that match, and you thus know that it can no longer contain exactly one item that matches.
You can work with filter
and pattern match on an list with exactly one item, and let this return True
, for the two other cases (the empty list, and a list with two or more items), we return False
, so:
single :: (a -> Bool) -> [a] -> Bool
single p a = case filter p a of
[_] -> True
_ -> False
This will prevent enumerating over the entire list if it can find two items that satisfy the given condition.