If I just have a very simple custom data type:
data Person = Person {first_name :: String,
last_name :: String
} deriving (Ord, Eq, Show)
If I have a list of these Person data types, and I want to sort it by last_name
if and only if the first_name
is the same. But I should not sort the first_name
. Simply call the following obviously doesn't work.
import Data.Function (on)
import Data.List (sortBy)
sortBy (compare `on` last_name ) persons
How can I solve it? I do agree it's quite confusing. What I want is that if I have the following (that's definitely not a list of the custom data type, I just want to show it clearly)
[("c","d"),("a","c"),("a","a")]
After sorting I would like to have
[("c","d"),("a","a"),("a","c")]
instead of
[("a","a"),("a","c"),("c","d")]
So the idea is that first element should still appear at first, since it does not have the same first_name
with the other two. Is that possible? Thanks!
The comparison function you want is to treat two
Person
values as equal if their first names are different. If the first names are the same, then compare based on the last name.Since
sort
in Haskell is stable, if an elementa
precedes an equal elementb
in the input, it will also precedeb
in the output. In this case, two elements with different first names will compare as equal, sosort
will really only sort the consecutive subsequences sharing a first name.There is probably a clever way to implement this, but a straightforward comparison function might look like
Given
people = [ Person "A" "B",Person "Z" "C",Person "Z" "A"]
, you can see the difference betweensortBy (comparing last_name)
andsortBy foo
.