kureta
kureta

Reputation: 483

How can I compare elements of two lists according to one predicate and select according to another?

What I am trying to achieve is to compare two lists of tuples with ((==) `on` fst) and out of the pairs that satisfy this predicate, select the ones that satisfy (min `on` snd)

Upvotes: 0

Views: 484

Answers (2)

duplode
duplode

Reputation: 34398

I will assume that...

What I am trying to achieve is to compare two lists of tuples with ((==) `on` fst)

... means comparing each pair in one list with the corresponding pair in the other list, as in the usual (==) for lists.

Here is a mostly pointfree (and perhaps slightly cranky) solution that stays close to your original suggestions:

-- Suggestions of sensible names for this are welcome.
yourSelector :: (Eq a, Ord b) => [(a, b)] -> [(a, b)] -> [(a, b)]
yourSelector ps = fmap (minBy' snd)
    . filter (uncurry ((==) `on` fst)) . zip ps
    where
    minBy' f (x, y) = case (compare `on` f) x y of
        LT -> x
        _ -> y
GHCi> yourSelector [(1,2),(3,5),(4,7)] [(1,3),(2,2),(4,9)]
[(1,2),(4,7)]

For alternative ways of writing minBy', cf. Maximizing according to a function.

Upvotes: 2

mnoronha
mnoronha

Reputation: 2625

To solve a general case, you can define modified version of filter that pattern-matches a tuple containing two predicates and checks if both are satisfied.

filter' :: ((a->Bool),(a->Bool)) -> [(a,a)] -> [(a,a)]
filter' (pred1,pred2) = foldr f []
 where f = (\x acc -> if pred1 $ fst x then
                                        if pred2 $ snd x then x : acc
                                        else acc
                      else acc
           )

Which would evaluate a list [(1,2),(2,2),(3,3),(3,4)] with the first predicate odd and the second predicate even as:

>> filter' (odd,even) [(1,2),(2,2),(3,3),(3,4)]
[(1,2),(3,4)]

Upvotes: 1

Related Questions