Enum.sort
sort
, go back to Enum module for more information.
Specs
Sorts the enumerable
according to Erlang's term ordering.
This function uses the merge sort algorithm. Do not use this
function to sort structs, see sort/2
for more information.
Examples
iex> Enum.sort([3, 2, 1])
[1, 2, 3]
Specs
sort( t(), (element(), element() -> boolean()) | :asc | :desc | module() | {:asc | :desc, module()} ) :: list()
Sorts the enumerable
by the given function.
This function uses the merge sort algorithm. The given function should compare
two arguments, and return true
if the first argument precedes or is in the
same place as the second one.
Examples
iex> Enum.sort([1, 2, 3], &(&1 >= &2))
[3, 2, 1]
The sorting algorithm will be stable as long as the given function
returns true
for values considered equal:
iex> Enum.sort(["some", "kind", "of", "monster"], &(byte_size(&1) <= byte_size(&2)))
["of", "some", "kind", "monster"]
If the function does not return true
for equal values, the sorting
is not stable and the order of equal terms may be shuffled.
For example:
iex> Enum.sort(["some", "kind", "of", "monster"], &(byte_size(&1) < byte_size(&2)))
["of", "kind", "some", "monster"]
Ascending and descending
sort/2
allows a developer to pass :asc
or :desc
as the sorting
function, which is a convenience for <=/2
and >=/2
respectively.
iex> Enum.sort([2, 3, 1], :asc)
[1, 2, 3]
iex> Enum.sort([2, 3, 1], :desc)
[3, 2, 1]
Sorting structs
Do not use </2
, <=/2
, >/2
, >=/2
and friends when sorting structs.
That's because the built-in operators above perform structural comparison
and not a semantic one. Imagine we sort the following list of dates:
iex> dates = [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]
iex> Enum.sort(dates)
[~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]
Note that the returned result is incorrect, because sort/1
by default uses
<=/2
, which will compare their structure. When comparing structures, the
fields are compared in alphabetical order, which means the dates above will
be compared by day
, month
and then year
, which is the opposite of what
we want.
For this reason, most structs provide a "compare" function, such as
Date.compare/2
, which receives two structs and returns :lt
(less-than),
:eq
(equal to), and :gt
(greater-than). If you pass a module as the
sorting function, Elixir will automatically use the compare/2
function
of said module:
iex> dates = [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]
iex> Enum.sort(dates, Date)
[~D[2019-01-01], ~D[2019-06-06], ~D[2020-03-02]]
To retrieve all dates in descending order, you can wrap the module in
a tuple with :asc
or :desc
as first element:
iex> dates = [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]
iex> Enum.sort(dates, {:asc, Date})
[~D[2019-01-01], ~D[2019-06-06], ~D[2020-03-02]]
iex> dates = [~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]
iex> Enum.sort(dates, {:desc, Date})
[~D[2020-03-02], ~D[2019-06-06], ~D[2019-01-01]]