Packages
map_sorter
0.1.17
0.2.70
0.2.69
0.2.68
0.2.67
0.2.66
0.2.65
0.2.64
0.2.63
0.2.62
0.2.61
0.2.60
0.2.59
0.2.58
0.2.57
0.2.56
0.2.55
0.2.54
0.2.53
0.2.52
0.2.51
0.2.50
0.2.49
0.2.48
0.2.47
0.2.46
0.2.45
0.2.44
0.2.42
0.2.41
0.2.40
0.2.39
0.2.38
0.2.37
0.2.36
0.2.35
0.2.34
0.2.33
0.2.32
0.2.31
0.2.30
0.2.29
0.2.28
0.2.27
0.2.26
0.2.25
0.2.24
0.2.23
0.2.22
0.2.21
0.2.20
0.2.19
0.2.18
0.2.17
0.2.16
0.2.15
0.2.14
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.22
0.1.21
0.1.20
0.1.19
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Sorts a list of maps per a list of sort specs.
Current section
Files
Jump to
Current section
Files
lib/map_sorter.ex
defmodule MapSorter do
@moduledoc """
Sorts a list of `maps` as per a list of `sort specs`
(ascending/descending keys).
Also supports:
- keywords
- structs implementing the Access behaviour
- nested maps, keywords or structs implementing the Access behaviour
"""
alias MapSorter.SortSpecs
require Logger
@doc """
Sorts `maps` as per its `sort specs` (compile time or runtime).
`sort specs` can be implicit, explicit or mixed:
- implicit: [:dob, :name] ≡ [asc: :dob, asc: :name]
- mixed: [:dob, desc: :name] ≡ [asc: :dob, desc: :name]
- explicit: [asc: :dob, desc: :name]
`sort specs` for nested data structures:
- implicit: [[:birth, :date], [:name, :first]]
- mixed: [[:birth, :date], desc: [:name, :first]]
- explicit: [asc: [:birth, :date], desc: [:name, :first]]
## Examples
iex> require MapSorter
iex> people = [
...> %{name: "Mike", likes: "movies" , dob: "1992-04-15"},
...> %{name: "Mary", likes: "travels", dob: "1992-04-15"},
...> %{name: "Bill", likes: "karate" , dob: "1977-08-28"},
...> %{name: "Joe" , likes: "boxing" , dob: "1977-08-28"},
...> %{name: "Jill", likes: "cooking", dob: "1976-09-28"}
...> ]
iex> sort_specs = [:dob, desc: :likes]
iex> MapSorter.log_level(:info) # :debug → debug messages
iex> sorted_people = %{
...> explicit: MapSorter.sort(people, asc: :dob, desc: :likes),
...> mixed: MapSorter.sort(people, [:dob, desc: :likes]),
...> runtime: MapSorter.sort(people, sort_specs)
...> }
iex> MapSorter.log_level(:info)
iex> sorted_people.explicit == sorted_people.mixed and
...> sorted_people.explicit == sorted_people.runtime and
...> sorted_people.explicit
[
%{name: "Jill", likes: "cooking", dob: "1976-09-28"},
%{name: "Bill", likes: "karate" , dob: "1977-08-28"},
%{name: "Joe" , likes: "boxing" , dob: "1977-08-28"},
%{name: "Mary", likes: "travels", dob: "1992-04-15"},
%{name: "Mike", likes: "movies" , dob: "1992-04-15"}
]
iex> require MapSorter
iex> people = [
...> %{name: "Mike", likes: "movies" , dob: "1992-04-15"},
...> %{name: "Mary", likes: "travels", dob: "1992-04-15"},
...> %{name: "Bill", likes: "karate" , dob: "1977-08-28"},
...> %{name: "Joe" , likes: "boxing" , dob: "1977-08-28"},
...> %{name: "Jill", likes: "cooking", dob: "1976-09-28"}
...> ]
iex> bad_specs = %{asc: :dob, desc: :likes}
iex> MapSorter.log_level(:info) # :debug → debug messages
iex> sorted_people = %{
...> literal: MapSorter.sort(people, %{asc: :dob, desc: :likes}),
...> runtime: MapSorter.sort(people, bad_specs)
...> }
iex> MapSorter.log_level(:info)
iex> sorted_people.literal == people and
...> sorted_people.runtime == people
true
"""
defmacro sort(maps, sort_specs) do
Logger.debug("sort specs: #{inspect(sort_specs)}...")
specs =
case sort_specs do
specs when is_list(specs) -> specs
specs -> Macro.expand(specs, __CALLER__) # in case module attribute
end
case SortSpecs.to_quoted(specs) do
{:ok, fun} -> quote do: Enum.sort(unquote(maps), unquote(fun))
{:error, bad_specs} ->
Logger.debug("bad sort specs: #{inspect(bad_specs)}")
maps
end
end
@doc """
Allows to change the log `level` at compile time.
"""
defmacro log_level(level), do: Logger.configure(level: level)
end