josvankamp
josvankamp

Reputation: 49

Filter a haskell list

This is the code i have:

    data Review = Review {  artiest :: String,
                    score :: Integer,
                    tour :: Tour,
                    datum :: String,
                    plaats :: String,
                    soortLocatie :: Locatie,
                    topSongs :: [String]
                   } deriving (Eq, Ord, Show)

    getBestLoc [] beste = beste
    getBestLoc (x:xs) beste
        | (score x) > beste = getBestLoc xs (score x)
        | otherwise = getBestLoc xs beste

What I'm trying to do is to get the review whit the best score, but I want the Locatie to be returned. Now I get the best score returned. How can i solve this?

EDIT

So this is the new function I tried

    tester :: [Review] -> Locatie
    tester = loc
        where mxscr = maximumBy (compare `on` score)
      loc = map soortLocatie mxscr

Upvotes: 0

Views: 130

Answers (2)

J. Abrahamson
J. Abrahamson

Reputation: 74344

While user2407038 provides a perfectly correct answer, I want to provide a solution written slightly differently for clarity.

You want to return the Locatie of the Review with the best score. That means that all the other information in Review is immaterial for this process. We should drop it.

simplifyReview :: Review -> (Integer, Locatie)
simplifyReview r = (score r, soortLocatie r)

Now we simply want to return the pair which has the largest fst element and then we can get the second one. We'll use maximumBy to search a list of our simplified reviews

import Data.List (maximumBy)

getBestPair :: [(Integer, Locatie)] -> (Integer, Locatie)
getBestPair pairs = maximumBy comparePairs pairs where
  comparePairs (score1, locatie1) (score2, locatie2) = compare score1 score2

Finally we can combine these pieces to make the desired function

getBestLocatie :: [Review] -> Locatie
getBestLocatie reviews = snd (getBestPair (map simplifyReview reviews))

Often you'll see this written in "function composition form"

getBestLocatie :: [Review] -> Locatie
getBestLocatie = snd . getBestPair . map simplifyReview

Upvotes: 1

user2407038
user2407038

Reputation: 14578

import Data.List (maximumBy)
import Data.Function (on)

getBestLoc :: [Review] -> Review
getBestLoc = maximumBy (compare `on` score)

This function will return the Review with the highest score. After that, getting any field of the resulting review is trivial; your desired function would be soortLocatie . getBestLoc.

A brief explanation of what is going on: according to the docs, on follows the property:

g `on` f = \x y -> f x `g` f y

so

compare `on` score == \x y -> score x `compare` score y

In other words, it compares the two scores, return one of LT, GT, EQ. Then, maximumBy takes a comparison function and a list, and returns the maximum according to the comparison function. You can think of it as maximum == maximumBy compare.

Upvotes: 3

Related Questions