Reputation: 51
I'm trying to write a function that chooses the tuple with the lower value and the tuple is formed by a word and a value.
For example, for a list of tuples like this one: [("CHURCH",262),("PENCIL",311),("FLOUR",175),("FOREST",405),("CLASS",105)], the function would return ("CLASS",105)
Can someone help me out? :)
Thank you so much!
Upvotes: 0
Views: 472
Reputation: 5709
I am Haskell beginner but I wanted to find a working solution anyway and came up with:
minTup' :: [(String, Int)] -> Maybe (String, Int) -> (String, Int)
minTup' [] (Just x)= x
minTup' (x:xs) Nothing = minTup' xs (Just x)
minTup' ((s,n):xs) (Just (s',n'))
| n < n' = minTup' xs (Just (s,n))
| otherwise = minTup' xs (Just (s',n'))
minTup :: [(String, Int)] -> (String, Int)
minTup [] = error "Need a list of (String,Int)"
minTup x = minTup' x Nothing
main = do
print $ minTup [("CHURCH",262),("PENCIL",311),("FLOUR",175),("FOREST",405),("CLASS",105)]
print $ minTup [("CHURCH",262)]
print $ minTup []
Upvotes: 1
Reputation: 54058
You're looking for the function minimumBy
in the Data.List
module. It's type is
minimumBy :: (a -> a -> Ordering) -> [a] -> a
In your case, it would also be useful to import comparing
from the Data.Ord
module, which has the type
comparing :: Ord a => (b -> a) -> b -> b -> Ordering
And this lets you give it an "accessor" function to create an ordering. So in this case you can do
minimumSnd :: [(String, Int)] -> (String, Int)
minimumSnd = minimumBy (comparing ???)
I'll let you fill in the ???
, it should be quite easy at this point. What would your accessor function passed to comparing
be for your type?
If you wanted to write a custom function for this instead, I would suggest using the fold
pattern. We can also take this opportunity to make it safer by returning a Maybe
type, and more general by not requiring it to be a list of (String, Int)
:
minimumSnd :: (Ord b) => [(a, b)] -> Maybe (a, b)
minimumSnd = go Nothing
where
-- If the list is empty, just return our accumulator
go acc [] = acc
-- If we haven't found a minimum yet, grab the first element and use that
go Nothing (x:xs) = go (Just x) xs
-- If we have a minimum already, compare it to the next element
go (Just currentMin) (x:xs)
-- If it's <= our current min, use it
| snd x <= snd currentMin = go (Just x) xs
-- otherwise keep our current min and check the rest of the list
| otherwise = go (Just currentMin) xs
Upvotes: 8
Reputation: 7360
Try this:
foldl1 (\acc x -> if snd x < snd acc then x else acc) <your list>
You fold your list by comparing the current element of the list to the next one. If the second value of the next element if smaller than the value of the current element, it is the new value for the accumulator. Else the accumulator stays the same. This process is repeated until the entire list has been traversed.
Upvotes: 1