I am trying to sort my list of tuples based on the 4th element in each of the tuples. The fourth element contains a string that is a person\'s name. I want to put tuples that c
Start with the type of sortBy
:
> :t sortBy
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
This means byName
needs to have type a -> a -> Ordering
. In this case, a
is a tuple whose fifth element as type String
; byName
will ignore the other fields. So you'll need to define a function like
type MyType = (String, Int, String, Int, String, Double)
byName :: MyType -> MyType -> Ordering
byName (_, _, _, _, a, _) (_, _, _, _, b, _) = ...
I leave replacing the ...
with the correct expression as an exercise.
(Recall that Ordering
is a type with three values, LT
, EQ
, and GT
, where byName a b == LT
if a < b
, byName a b == EQ
if a == b
, and byName a b == GT
if a > b
. In your case, two tuples will compare as equal as long as they have the same name. It sounds like you don't actually care whether byName
returns LT
or GT
otherwise.)
While you can figure something like this out for yourself, most of the desired capability is already available via Data.Ord
. If tuples
is your input list, you can just use:
sortBy (comparing name) tuples
where name
is a utility function defines as:
name (_, _, _, _, n, _) = n
This is actually a parametrically polymorphic function, so you could also call it fifth
, or something generic like that.
You can call the above expression and format the output to see that it does approximately what you want:
Prelude Data.Ord Data.List> putStrLn $ unlines $ show <$> sortBy (comparing name) tuples
("B",101,"M",3,"Jon",3.33)
("B",273,"F",1,"Mike",2.66)
("B",203,"R",3,"Rachel",1.66)
("A",200,"P",1,"Rachel",0.0)
("A",999,"N",3,"Rachel",1.33)
("A",100,"Q",3,"Todd",2.0)
("A",549,"D",3,"Todd",2.0)
("B",220,"S",3,"Todd",4.0)
Compared to the OP, this is in the opposite order of what's required, but I'll leave it as an exercise to figure out how to change the sort order. There's a couple of different ways to do that.