Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort a list of tuples by their first index in Elm

Assuming that I have a list of tuples that resemble the following example:

[(5, "a"), (1, "c"), (7, "d")] 

in Elm, how do I go about sorting the list in ascending order by their first elements so that we get the following result?

[(1, "c"), (5, "a"), (7, "d")]

Using the Elm List documentation, it appears that the sortBy and sortWith functions will be useful for this case. My attempt at an implementation is as follows:

maxTuples : Tuple(a, b) -> Tuple(a, b) -> Tuple(a, b)
maxTuples t1 t2 = 
    case compare t1 t2 of 
        ((Tuple.first t1) >= (Tuple.first t2)) -> GT
         _                                     -> LT


sortByFirst : List (Tuple (a, b)) -> List (Tuple (a, b))
sortByFirst lst = 
    List.sortWith maxTuples lst

However, I'm getting compiler errors of the following nature:

I ran into something unexpected when parsing your code!

99|         ((Tuple.first t1) >= (Tuple.first t2)) -> GT
                ^
I am looking for one of the following things:

an upper case name

My hunch would be that the compiler is looking for GT/LT/EQ per the API of List library, but if this the case I'm not sure how we would be able to use either sortBy or sortWith to sort a list of Tuples in Elm by the first index of each element.

like image 279
Adam Freymiller Avatar asked Jan 04 '23 03:01

Adam Freymiller


1 Answers

You found the right functions. In your code, there are actually multiple problems:

  1. The type annotations should be just (a, b), not Tuple(a, b).
  2. You compare t1 with t2, which will compare the tuples lexicographically. You actually want compare (Tuple.first t1) (Tuple.first t2)
  3. The case branches require a pattern before the ->. In this case would be something like EQ, since you are matching on the result of compare, which returns Order type.

You could fix the code like this:

maxTuples : (comparable, b) -> (comparable, b) -> (comparable, b)
maxTuples t1 t2 = 
    case compare (Tuple.first t1) (Tuple.first t2) of 
        GT -> GT
        EQ -> EQ
         _ -> LT

But now there is an unnecessary repetition, you are simply returning the result of compare function.

maxTuples t1 t2 = 
    compare (Tuple.first t1) (Tuple.first t2)

Together with the sort function, it would look like this:

sortByFirst lst = 
    List.sortWith (\t1 t2 -> compare (Tuple.first t1) (Tuple.first t2)) lst

It turns out this kind of operation is quite common, especially with lists of records. For this reason, Elm offers another function – sortBy. It takes a function and compares the elements after applying the function:

sortBy f lst =
    List.sortWith (\a b -> compare (f a) (f b)) lst

You can therefore use sortBy function to greatly simplify the code:

sortByFirst : List (comparable, b) -> List (comparable, b)
sortByFirst =
    sortBy Tuple.first
like image 145
Jan Tojnar Avatar answered Jan 12 '23 03:01

Jan Tojnar