Is there a better and more concise way to write the following code in Haskell? I've tried using if..else
but that is getting less readable than the following. I want to avoid traversing the xs
list (which is huge!) 8 times to just separate the elements into 8 groups. groupBy
from Data.List
takes only one test condition function: (a -> a -> Bool) -> [a] -> [[a]]
.
x1 = filter (check condition1) xs
x2 = filter (check condition2) xs
x3 = filter (check condition3) xs
x4 = filter (check condition4) xs
x5 = filter (check condition5) xs
x6 = filter (check condition6) xs
x7 = filter (check condition7) xs
x8 = filter (check condition8) xs
results = [x1,x2,x3,x4,x5,x6,x7,x8]
This only traverses the list once:
import Data.Functor
import Control.Monad
filterN :: [a -> Bool] -> [a] -> [[a]]
filterN ps =
map catMaybes . transpose .
map (\x -> map (\p -> x <$ guard (p x)) ps)
For each element of the list, the map
produces a list of Maybe
s, each Maybe
corresponding to one of the predicates; it is Nothing
if the element does not satisfy the predicate, or Just x
if it does satisfy the predicate. Then, the transpose
shuffles all these lists so that the list is organised by predicate, rather than by element, and the map catMaybes
discards the entries for elements that did not satisfy a predicate.
Some explanation: x <$ m
is fmap (const x) m
, and for Maybe
, guard b
is if b then Just () else Nothing
, so x <$ guard b
is if b then Just x else Nothing
.
The map
could also be written as map (\x -> [x <$ guard (p x) | p <- ps])
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With