Reputation: 311
I have a high order function which would take:
results ["Red", "Blue", "Green", "Blue", "Blue", "Red"]
And return:
[(1,"Green"),(2,"Red"),(3,"Blue")]
I need to use the results function and create a new function called winner:
winner :: [Party ] -> Party
winner xs =
which would output the most occurred colour and remove first element within tuples, if two colours have the same occurrences it output two the colours, for example:
winner ["Red", "Blue", "Green", "Blue", "Blue", "Red"]
output:
"blue"
so far I've tried using snd and tail but I keep getting errors. Thank you in advance.
Upvotes: 2
Views: 3060
Reputation: 54574
If you want to avoid sorting, you could use a MultiSet, which has a finMax
function.
Upvotes: 3
Reputation: 51
import Data.List
import Data.Ord
winner xs = head . maximumBy (comparing length) . group . sort $ xs
main = print $ winner ["Red", "Blue", "Green", "Blue", "Blue", "Red"]
looks like the most direct way.
Upvotes: 5
Reputation: 183858
If you have the results
function, a simple application of
maximumBy :: (a -> a -> Ordering) -> [a] -> a
would suffice
import Data.List -- for maximumBy
import Data.Ord -- for comparing
winner = snd . maximumBy (comparing fst) . results
Seeing
if two colours have the same occurrences it output two the colours
you need a different type - and of course a different implementation, still easy with library functions, though:
import Data.List
import Data.Ord
import Data.Function
winners :: [Party] -> [Party]
winners = map snd . head . groupBy ((==) `on` fst) . sortBy (flip $ comparing fst) . results
Since results
already produces a sorted list - I didn't want to rely on that just from the example output - it is not necessary to sort again, and we can use
winners = map snd . last . groupBy ((==) `on` fst) . results
to produce the list of all most occurring elements. If only one most frequent element is desired, it could be obtained with
winner = snd . last . results
from the sorted frequency list.
Upvotes: 10
Reputation: 5176
In the winners
function, you get the list of String
, which you can then transform into a list of ´(Int, String)´ tuples by applying the results
function. You then want to take the last of those tuples (assuming that results
returns the elements in ascending order of number of occurrences) and return the second element of that tuple. You already mention that you have tried the snd
function, so the only trouble is with the middle step, getting the last element of the list of tuples, correct?
What should be the type of the function that returns that last element? It takes a list of (Int, String)
tuples and returns a single tuple, so one guess at the type could be [(Int, String)] -> (Int, String)
, but the function doesn't really need to know that it is dealing with tuples inside the list. It just needs to return the last element of a list, so a better type might be [a] -> a
. Armed with this type, go to Hoogle and type it in the search box, and you get the function you need as the second result.
This should suffice for a winners function that only returns a single result. If you want to be able to return more than one result, then - as Daniel Fischer notes in his answer - you need another signature and a slightly more complex implementation. I think the simplest thing would be to find all the tuples which have the same occurrence as the last tuple (again assuming ascending order of occurrences) by filtering out those tuples which don't have the maximum number of occurrences, and then convert the resulting list of tuples to a list of the second elements of those tuples, by mapping snd
over the list:
winners :: [String] -> [String]
winners xs = map snd maxOccursTuples
where maxOccursTuples = filter isMaxOccursTuple occurrences
isMaxOccursTuple tuple = fst tuple == maxOccurs
maxOccurs = fst (last occurrences)
occurrences = results xs
Upvotes: 1