Skip to content
Discussions/App Development/How can I sort a list from high to lowForum ↗

How can I sort a list from high to low

App Development6 posts242 viewsLast activity Mar 2022
CO
cohen.avrahamOP
Mar 2022

G-d willing

Hello,
How can I sort a list of Decimal values from highest to lowest without removing the duplicated values?
The sort function arranges the elements from lowest to highest and it does not get any additional parameter that defines the sorting order (ascending or descending),
I looked on the DA.List soring functions and I didn’t find anything that match

Thanks,

BE
bernhard
Mar 2022

You can use a custom ordering with the sortBy function. For something with an existing ordering that you can use <, > etc on, you can use compare to get your hands on that ordering. So to sort descending (the default is ascending), you can define a descending ordering like this:

module Main where

import DA.Assert
import DA.List
import Daml.Script

descending : Ord a => a -> a -> Ordering
descending a b = case compare a b of
  EQ -> EQ
  GT -> LT
  LT -> GT

t = script do
  let 
    xs = [15,67,7,8,1,7,1]
    sorted = sort xs
    reversed = reverse sorted
    sortedDesc = sortBy descending xs
  reversed === sortedDesc
GA
Gary_Verhaegen
Mar 2022

@bernhard’s answer is the most general, but there are two other approaches that can be used for this specific case. The first one is actually present in @bernhard’s code: the reverse function. You can use (reverse . sort) instead of sort to get what you want.

The other alternative is the DA.List.sortOn function. Whereas sortBy takes a a -> a -> Ordering function, i.e. a function that compares two elements, sortOn takes a (Ord k) => a -> k function, i.e. a function that takes a single element of the list and transforms it into something sortable. In this particular case, you can sort on the opposite: sortOn negate. The more general function Down reverses the ordering for any ordered data type (whereas negate only negates numbers).

module Main where

import Daml.Script
import qualified DA.List

revSort1 : (Ord a) => [a] -> [a]
revSort1 = reverse . DA.List.sort

revSort2 : (Number a, Ord a) => [a] -> [a]
revSort2 = DA.List.sortOn negate

revSort3 : (Ord a) => [a] -> [a]
revSort3 = DA.List.sortOn Down

setup : Script ()
setup = script do
  let list = [1.0, 2.0, 3.0, 3.0] : [Decimal]
  let revList = [3.0, 3.0, 2.0, 1.0] : [Decimal]
  assert $ revSort1 list == revList
  assert $ revSort2 list == revList
  assert $ revSort3 list == revList
  assert $ (reverse . DA.List.sort) list == revList
  assert $ (DA.List.sortOn negate) list == revList
  assert $ (DA.List.sortOn Down) list == revList
  pure ()
CO
cohen.avraham
Mar 2022

I am totally embarrassed about me forgetting the reverse function. And if I was remembering it, I wouldn’t post this question in the first place.

@bernhard thanks for your answer. Regarding the ability to implement my own compare method, I know that as I did it before, However, I was more into finding an existing function that can do the descending order by one call only.
I guess calling reverse is quite clear about what the command is performing. But calling the reverse function on top of the sort function is basically 2 operations that can cost performance (depends on the list’ length).

@Gary_Verhaegen, I have to say that I have learned new things from your answer as I wasn’t aware of the negate and Down

GA
Gary_Verhaegen
Mar 2022

Re: performance, in principle (I haven’t personally checked the Daml implementations), sorting is O(nlog(n)), and reversing is O(n). So doing both ends up being O((log(n)+1)n), which isn’t all that bad. Yes, technically, it will be slower, but it’s unlikely to be the bottleneck in a real application.

SO
Sofia_Faro
Mar 2022

Regarding performance, if you want to sort quickly I recommend using DA.List.BuiltinOrder, which compares values using the built-in order from Daml LF. To sort numbers in reverse order, use sortOn negate like @Gary_Verhaegan suggested:

import qualified DA.List.BuiltinOrder

sortReverse : [Decimal] -> [Decimal]
sortReverse = DA.List.BuiltinOrder.sortOn negate

Note that in this case, sortOn Down will not work as expected, because the built-in order of Daml LF will ignore the custom order that Down tries to use.

← Back to Discussions