Enum.min_by/max_by returns the values of type Decimal vise versa

In “Product” a model I have “price” of type https://github.com/ericmj/decimal

This code finds min and max prices, but precisely in the opposite way:

      min = Enum.min_by(products, &(&1.price)).price
      max = Enum.max_by(products, &(&1.price)).price

“min” contains the biggest price, “max” the smallest one. Why?

Enum.min_by/2 and Enum.max_by/2 work using Kernel.</2 and Kernel.>/2 respectively. You can’t use those to compare Decimal (or about any other struct).

You need to Enum.reduce/3 using Decimal.max/2/Decimal.min/2, eg:

def minimal_decimal(products) do
  Enum.reduce(tl(products), hd(products).price, &Decimal.min(&1.price, &2))
end
3 Likes

Why not to sort instead using Decimal.mix/max or Decimal.cmp?

Because Enum.reduce/3 is O(n), sorting is O(n log n) at least. Reading the last element from a list is O(n) again. So sorting and taking out the values is unnecessarily slow, compared to a single pass.

2 Likes

That’s true for large lists. If I had a list 10-50-100 elements, sorting would be simpler, right? A differnce in performance wouldn’t be noticiable

Perhaps…

But as I do not know your input, and also assume that especially lists can become arbitrarily large, I’d strictly prefer the reduce.

Usually, I’d even create a min_max version, which gives me minimal and maximal value of the list in a single pass.

1 Like