Reputation: 1707
I've been having this problem a lot recently in some form or another. Lets say that I want to take a number x and apply a bunch of high order functions to x producing y. I then check to see if y satisfies a certain property, if it does, then I want to return x.
This problem seems to get really tricky when I have a list of numbers [x1,x2..xn] and the functions I apply condense the list. For example, I apply a function to each of the elements in the list (producing [y1,y2..]), sort, group, and then I want to return the values of x for the largest group. For example:
head . reverse . sort . map (length) . group . sort . map (mod 4) $ [1..10]
The answer is 6, but how would I rewrite a function like this to tell me which elements numbers 1 through 10 belong to those 6?
I've played with the idea of passing tuples and using fst everywhere until the snd is required, or writing a new class to make it so something like sort only works on one element of the class, but I can't seem to come up with a clean approach
Thanks for the help.
Upvotes: 3
Views: 260
Reputation: 204808
You may be interested in GHC's TransformListComp
extension, which enables a direct way to express your query.
{-# LANGUAGE TransformListComp #-}
import GHC.Exts
input = [1..10]
output = [ x
| x <- input
, let y = 4 `mod` x
, then group by y
, then sortWith by (-length x, the y)
]
-- output = [[5,6,7,8,9,10],[1,2,4],[3]]
Upvotes: 1
Reputation: 30969
Here's a small set of changes to your code that return the value rather than the length; the use of the *By
functions avoids the need to use tuples:
maximumBy (compare `on` length) . groupBy ((==) `on` mod 4) . sortBy (compare `on` mod 4) $ [1..10]
This code requires Data.List and Data.Function. Data.Function includes on
, which allows a comparison (for sorting or grouping) to be applied to some function of the input.
Upvotes: 5