Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Haskell, how can I use the built in sortBy function to sort a list of pairs(tuple)?

I am a beginner in Haskell so please bear with me. (Just started learning yesterday!) How can I sort a list of tuples primarily by their first components (highest to smallest) and secondarily by their second components (smallest to highest)? A sample input/output would be:

[(1, "b"), (1, "a"), (2, "b"), (2, "a")] (input)

[(1, "a"), (2, "a"), (1, "b"), (2, "b")] (middle step)

[(2, "a"), (2, "b"), (1, "a"), (1, "b")] (output)

I tried using the following but it gave wrong output:

sortGT a b = GT  sortBy sortGT lst 

I am sure that I can do this by using sortBy only, but I can't figure it out myself. Any help would be highly appreciated!

like image 589
eclipseNoob Avatar asked Feb 28 '10 02:02

eclipseNoob


People also ask

How do you use sortBy in Haskell?

The sortBy function is the non-overloaded version of sort. >>> sortBy (\(a,_) (b,_) -> compare a b) [(2, "world"), (4, "!"), (1, "Hello")] [(1,"Hello"),(2,"world"),(4,"!")] sortBy sorts the specified Seq according to the specified comparator.

What does sort do in Haskell?

The sort function takes a list as the input and returns the sorted list as the output. The sort function sorts the elements of the given list in ascending order and returns it as a new list. The sort function is available in Data.


2 Answers

You need to construct your function sortGT, so that it compares pairs the way you want it:

sortGT (a1, b1) (a2, b2)   | a1 < a2 = GT   | a1 > a2 = LT   | a1 == a2 = compare b1 b2 


Using this you get the following results (I used ghci):

*Main Data.List> sortBy sortGT [(1, "b"), (1, "a"), (2, "b"), (2, "a")] [(2,"a"),(2,"b"),(1,"a"),(1,"b")] 
like image 103
3lectrologos Avatar answered Oct 21 '22 14:10

3lectrologos


May I suggest the following?

import Data.List (sortBy) import Data.Monoid (mconcat)  myPredicate (a1, a2) (b1, b2) = mconcat [compare b1 a1, compare a2 b2] 

You can then sort by writing sortBy myPredicate lst. The function mconcat simply scans through the list and obtains the first non-EQ occurence (or EQ if all elements are EQ and thus both pairs are considered equal).

On second thought, building the list isn't necessary.

import Data.List (sortBy) import Data.Monoid (mappend)  myPredicate (a1, a2) (b1, b2) = compare b1 a1 `mappend` compare a2 b2 

The definition of mappend for Ordering is essentially:

EQ `mappend` x = x x  `mappend` _ = x 

Which is exactly what we need.

Just for fun, generalizing gbacon's answer and making the use a little more flexible:

import Data.Ord import Data.List import Data.Monoid  ascending  = id descending = flip  sortPairs f x g y = f (comparing x) `mappend` g (comparing y)  mySort = sortBy (sortPairs descending fst ascending snd) 
like image 35
fredoverflow Avatar answered Oct 21 '22 12:10

fredoverflow