defmodule Algo do
@moduledoc """
A collection of utility functions for working with lists, maps, keyword lists, and strings.
This module is a convenience wrapper around the various `Algo` submodules, providing a single
namespace for importing functions.
"""
@doc group: "Map and keyword list functions"
defdelegate evolve(map, evolution_map), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate invert(map), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate get_paths(map), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate has_path?(map, path), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate get_path(map, path, default \\ nil), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate fetch_path(map, path), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate fetch_path!(map, path), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate put_path(map, path, value), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate put_new_path(map, path, value), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate replace_path(map, path, value), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate replace_path!(map, path, value), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate update_path(map, path, initial, fun), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate update_path!(map, path, fun), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate delete_path(map, path), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate get_values_at_paths(map, paths), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate path_satisfies?(map, path, fun), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate merge_right(left_map, right_map), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate merge_left(left_map, right_map), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate deep_merge_left(left_map, right_map), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate deep_merge_right(left_map, right_map), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate deep_merge_with(left_map, right_map, fun), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate get_depth(map), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate each_depth_first(map, fun), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate each_breadth_first(map, fun), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate project(list_of_maps, keys), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate where_all?(map, condition_map), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate where_any?(map, condition_map), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate where_eq?(map, condition_map), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate prop(name), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate props(names), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate rename_keys(map, renames), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate unnest_keys(map), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate stringify_keys(map), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate atomise_keys_with(map, key_fun), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate atomize_keys_with(map, key_fun), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate equivalent?(map, kw_list), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate as_map(kw_list), to: Algo.Assoc
@doc group: "Map and keyword list functions"
defdelegate as_keyword_list(map), to: Algo.Assoc
@doc group: "List functions"
defdelegate interweave(list1, list2), to: Algo.List
@doc group: "List functions"
defdelegate get_cartesian_product(list1, list2, output_as), to: Algo.List
@doc group: "List functions"
defdelegate get_permutations(list), to: Algo.List
@doc group: "List functions"
defdelegate get_subsequences(list), to: Algo.List
@doc group: "List functions"
defdelegate get_unique_pairs(list, output_as), to: Algo.List
@doc group: "List functions"
defdelegate map_accum(list, acc, fun), to: Algo.List
@doc group: "List functions"
defdelegate map_accum_right(list, acc, fun), to: Algo.List
@doc group: "List functions"
defdelegate chunk_while_adjacent(list, fun), to: Algo.List
@doc group: "List functions"
defdelegate split_whenever(list, fun), to: Algo.List
@doc group: "List functions"
defdelegate transpose(rows), to: Algo.List
@doc group: "List functions"
defdelegate move_at(list, from_index, to_index), to: Algo.List
@doc group: "List functions"
defdelegate unique_with(enumerable, fun), to: Algo.List
@doc group: "List functions"
defdelegate index_by(enumerable, fun), to: Algo.List
@doc group: "List functions"
defdelegate reduce_by(enumerable, key_fun, initial_acc, reduce_fun), to: Algo.List
@doc group: "List functions"
defdelegate unwind(enumerable, field), to: Algo.List
@doc group: "List functions"
defdelegate partition_map(enumerable, fun), to: Algo.List
@doc group: "List functions"
defdelegate difference_by(left, right, key_fun), to: Algo.List
@doc group: "List functions"
defdelegate difference_with(left, right, fun), to: Algo.List
@doc group: "List functions"
defdelegate intersect_by(left, right, key_fun), to: Algo.List
@doc group: "List functions"
defdelegate intersect_with(left, right, fun), to: Algo.List
@doc group: "List functions"
defdelegate get_symmetric_difference_by(left, right, key_fun), to: Algo.List
@doc group: "List functions"
defdelegate get_symmetric_difference_with(left, right, fun), to: Algo.List
@doc group: "List functions"
defdelegate inner_join(left, right, fun), to: Algo.List
@doc group: "String functions"
defdelegate humanise(str), to: Algo.String
@doc group: "String functions"
defdelegate humanize(str), to: Algo.String, as: :humanise
@doc """
Returns a comparator that checks equality after applying a function.
## Examples
iex> same_length? = Algo.eq_by?(&String.length/1)
iex> same_length?.("a", "b")
true
iex> same_length? = Algo.eq_by?(&String.length/1)
iex> same_length?.("a", "bb")
false
iex> Algo.unique_with(["a", "bb", "c"], Algo.eq_by?(&String.length/1))
["a", "bb"]
"""
@doc group: "Higher-order functions"
@spec eq_by?((any -> any)) :: (any, any -> boolean)
def eq_by?(fun) when is_function(fun, 1) do
fn left, right -> fun.(left) == fun.(right) end
end
@doc """
Returns whether all elements are unique after applying a function.
## Examples
iex> Algo.all_different_by?(["a", "bb", "ccc"], &String.length/1)
true
iex> Algo.all_different_by?(["a", "b"], &String.length/1)
false
"""
@doc group: "Enumerable functions"
@spec all_different_by?(Enumerable.t(), (any -> any)) :: boolean
def all_different_by?(enumerable, fun) do
Enum.count(Enum.uniq_by(enumerable, fun)) == Enum.count(enumerable)
end
@doc """
Returns whether every element in an enumerable is unique.
## Examples
iex> Algo.all_different?([1, 2, 3])
true
iex> Algo.all_different?([1, 2, 1])
false
"""
@doc group: "Enumerable functions"
@spec all_different?(Enumerable.t()) :: boolean
def all_different?(enumerable) do
all_different_by?(enumerable, & &1)
end
defmodule Alt do
@moduledoc """
Provides alternative non-verb names for functions in Algo.
These better reflect the purity of functions and immutability of data structures.
"""
@doc """
Alias for `Algo.evolve/2`.
"""
defdelegate evolved(map, evolution_map), to: Algo, as: :evolve
@doc """
Alias for `Algo.invert/1`.
"""
defdelegate inverted(map), to: Algo, as: :invert
@doc """
Alias for `Algo.get_paths/1`.
"""
defdelegate paths(map), to: Algo, as: :get_paths
@doc """
Alias for `Algo.has_path?/2`.
"""
defdelegate has_path?(map, path), to: Algo, as: :has_path?
@doc """
Alias for `Algo.get_path/3`.
"""
defdelegate maybe_value_at_path(map, path, default \\ nil), to: Algo, as: :get_path
@doc """
Alias for `Algo.fetch_path/2`.
"""
defdelegate value_at_path(map, path), to: Algo, as: :fetch_path
@doc """
Alias for `Algo.fetch_path!/2`.
"""
defdelegate value_at_path!(map, path), to: Algo, as: :fetch_path!
@doc """
Alias for `Algo.put_path/3`.
"""
defdelegate with_path(map, path, value), to: Algo, as: :put_path
@doc """
Alias for `Algo.put_new_path/3`.
"""
defdelegate with_new_path(map, path, value), to: Algo, as: :put_new_path
@doc """
Alias for `Algo.replace_path/3`.
"""
defdelegate with_replaced_path(map, path, value), to: Algo, as: :replace_path
@doc """
Alias for `Algo.replace_path!/3`.
"""
defdelegate with_replaced_path!(map, path, value), to: Algo, as: :replace_path!
@doc """
Alias for `Algo.update_path/4`.
"""
defdelegate with_updated_path(map, path, initial, fun), to: Algo, as: :update_path
@doc """
Alias for `Algo.update_path!/3`.
"""
defdelegate with_updated_path!(map, path, fun), to: Algo, as: :update_path!
@doc """
Alias for `Algo.delete_path/2`.
"""
defdelegate without_path(map, path), to: Algo, as: :delete_path
@doc """
Alias for `Algo.get_values_at_paths/2`.
"""
defdelegate values_at_paths(map, paths), to: Algo, as: :get_values_at_paths
@doc """
Alias for `Algo.path_satisfies?/3`.
"""
defdelegate path_satisfies?(map, path, fun), to: Algo, as: :path_satisfies?
@doc """
Alias for `Algo.merge_right/2`.
"""
defdelegate right_merged(left_map, right_map), to: Algo, as: :merge_right
@doc """
Alias for `Algo.merge_left/2`.
"""
defdelegate left_merged(left_map, right_map), to: Algo, as: :merge_left
@doc """
Alias for `Algo.deep_merge_left/2`.
"""
defdelegate deep_left_merged(left_map, right_map), to: Algo, as: :deep_merge_left
@doc """
Alias for `Algo.deep_merge_right/2`.
"""
defdelegate deep_right_merged(left_map, right_map), to: Algo, as: :deep_merge_right
@doc """
Alias for `Algo.deep_merge_with/3`.
"""
defdelegate deep_merged_with(left_map, right_map, fun), to: Algo, as: :deep_merge_with
@doc """
Alias for `Algo.get_depth/1`.
"""
defdelegate depth(map), to: Algo, as: :get_depth
@doc """
Alias for `Algo.each_depth_first/2`.
"""
defdelegate each_depth_first(map, fun), to: Algo, as: :each_depth_first
@doc """
Alias for `Algo.each_breadth_first/2`.
"""
defdelegate each_breadth_first(map, fun), to: Algo, as: :each_breadth_first
@doc """
Alias for `Algo.project/2`.
"""
defdelegate projection(list_of_maps, keys), to: Algo, as: :project
@doc """
Alias for `Algo.where_all?/2`.
"""
defdelegate where_all?(map, condition_map), to: Algo, as: :where_all?
@doc """
Alias for `Algo.where_any?/2`.
"""
defdelegate where_any?(map, condition_map), to: Algo, as: :where_any?
@doc """
Alias for `Algo.where_eq?/2`.
"""
defdelegate where_eq?(map, condition_map), to: Algo, as: :where_eq?
@doc """
Alias for `Algo.interweave/2`.
"""
defdelegate interwoven(list1, list2), to: Algo, as: :interweave
@doc """
Alias for `Algo.get_cartesian_product/3`.
"""
defdelegate cartesian_product(list1, list2, output_as), to: Algo, as: :get_cartesian_product
@doc """
Alias for `Algo.get_permutations/1`.
"""
defdelegate permutations(list), to: Algo, as: :get_permutations
@doc """
Alias for `Algo.get_subsequences/1`.
"""
defdelegate subsequences(list), to: Algo, as: :get_subsequences
@doc """
Alias for `Algo.get_unique_pairs/2`.
"""
defdelegate unique_pairs(list, output_as), to: Algo, as: :get_unique_pairs
@doc """
Alias for `Algo.map_accum/3`.
"""
defdelegate accumulated_map(list, acc, fun), to: Algo, as: :map_accum
@doc """
Alias for `Algo.map_accum_right/3`.
"""
defdelegate right_accumulated_map(list, acc, fun), to: Algo, as: :map_accum_right
@doc """
Alias for `Algo.chunk_while_adjacent/2`.
"""
defdelegate adjacent_chunks(list, fun), to: Algo, as: :chunk_while_adjacent
@doc """
Alias for `Algo.split_whenever/2`.
"""
defdelegate split_whenever(list, fun), to: Algo, as: :split_whenever
@doc """
Alias for `Algo.transpose/1`.
"""
defdelegate transposed(rows), to: Algo, as: :transpose
@doc """
Alias for `Algo.move_at/3`.
"""
defdelegate with_moved_elem(list, from_index, to_index), to: Algo, as: :move_at
@doc """
Alias for `Algo.unique_with/2`.
"""
defdelegate unique_with(enumerable, fun), to: Algo, as: :unique_with
@doc """
Alias for `Algo.index_by/2`.
"""
defdelegate indexed_by(enumerable, fun), to: Algo, as: :index_by
@doc """
Alias for `Algo.reduce_by/4`.
"""
defdelegate reduced_by(enumerable, key_fun, initial_acc, reduce_fun), to: Algo, as: :reduce_by
@doc """
Alias for `Algo.unwind/2`.
"""
defdelegate unwound(enumerable, field), to: Algo, as: :unwind
@doc """
Alias for `Algo.partition_map/2`.
"""
defdelegate partitioned_map(enumerable, fun), to: Algo, as: :partition_map
@doc """
Alias for `Algo.difference_by/3`.
"""
defdelegate difference_by(left, right, key_fun), to: Algo, as: :difference_by
@doc """
Alias for `Algo.difference_with/3`.
"""
defdelegate difference_with(left, right, fun), to: Algo, as: :difference_with
@doc """
Alias for `Algo.intersect_by/3`.
"""
defdelegate intersection_by(left, right, key_fun), to: Algo, as: :intersect_by
@doc """
Alias for `Algo.intersect_with/3`.
"""
defdelegate intersection_with(left, right, fun), to: Algo, as: :intersect_with
@doc """
Alias for `Algo.get_symmetric_difference_by/3`.
"""
defdelegate symmetric_difference_by(left, right, key_fun), to: Algo, as: :get_symmetric_difference_by
@doc """
Alias for `Algo.get_symmetric_difference_with/3`.
"""
defdelegate symmetric_difference_with(left, right, fun), to: Algo, as: :get_symmetric_difference_with
@doc """
Alias for `Algo.inner_join/3`.
"""
defdelegate inner_join(left, right, fun), to: Algo, as: :inner_join
@doc """
Alias for `Algo.all_different_by?/2`.
"""
defdelegate all_different_by?(enumerable, fun), to: Algo, as: :all_different_by?
@doc """
Alias for `Algo.eq_by?/1`.
"""
defdelegate eq_by?(fun), to: Algo, as: :eq_by?
@doc """
Alias for `Algo.all_different?/1`.
"""
defdelegate all_different?(enumerable), to: Algo, as: :all_different?
@doc """
Alias for `Algo.prop/1`.
"""
defdelegate prop(name), to: Algo, as: :prop
@doc """
Alias for `Algo.props/1`.
"""
defdelegate props(names), to: Algo, as: :props
@doc """
Alias for `Algo.rename_keys/2`.
"""
defdelegate with_renamed_keys(map, renames), to: Algo, as: :rename_keys
@doc """
Alias for `Algo.unnest_keys/1`.
"""
defdelegate with_unnested_keys(map), to: Algo, as: :unnest_keys
@doc """
Alias for `Algo.stringify_keys/1`.
"""
defdelegate with_stringified_keys(map), to: Algo, as: :stringify_keys
@doc """
Alias for `Algo.atomise_keys_with/2`.
"""
defdelegate with_atomised_keys(map, key_fun), to: Algo, as: :atomise_keys_with
@doc """
Alias for `Algo.atomize_keys_with/2`.
"""
defdelegate with_atomized_keys(map, key_fun), to: Algo, as: :atomize_keys_with
@doc """
Alias for `Algo.equivalent?/2`.
"""
defdelegate equivalent?(map, kw_list), to: Algo, as: :equivalent?
@doc """
Alias for `Algo.as_map/1`.
"""
defdelegate as_map(kw_list), to: Algo, as: :as_map
@doc """
Alias for `Algo.as_keyword_list/1`.
"""
defdelegate as_keyword_list(map), to: Algo, as: :as_keyword_list
@doc """
Alias for `Algo.humanise/1`.
"""
defdelegate humanised(str), to: Algo, as: :humanise
@doc """
Alias for `Algo.humanize/1`.
"""
defdelegate humanized(str), to: Algo, as: :humanize
end
end