README.md

# ex_aequo

<!--
DO NOT EDIT THIS FILE
It has been generated from the template `README.md.eex` by Extractly (https://github.com/RobertDober/extractly.git)
and any changes you make in this file will most likely be lost
-->

[![CI](https://github.com/RobertDober/ex_aequo/actions/workflows/ci.yml/badge.svg)](https://github.com/RobertDober/ex_aequo/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/RobertDober/ex_aequo/badge.svg?branch=master)](https://coveralls.io/github/RobertDober/ex_aequo?branch=master)
[![Hex.pm](https://img.shields.io/hexpm/v/ex_aequo.svg)](https://hex.pm/packages/ex_aequo)
[![Hex.pm](https://img.shields.io/hexpm/dw/ex_aequo.svg)](https://hex.pm/packages/ex_aequo)
[![Hex.pm](https://img.shields.io/hexpm/dt/ex_aequo.svg)](https://hex.pm/packages/ex_aequo)

ExAequo Elixir Tools

Meaning of the name. All nice latin expressions starting with _Ex_ are consumed at an alarming rate, so, all things
being equal, I choose this one.

## ExAequo.Enum offers some extension functions for Elixir's Enum module

### Grouped Accumulation

Groupes accumulated values of an Enum according to a function that
indicates if two consequent items are of the same kind and if so
how to accumulate their two values.

The `grouped_reduce` function returns the groupes in reverse order, as,
during traversal of lists quite often reversing the result of the 
classical "take first and push a function of it to the result" pattern
cancels out.

An optional, `reverse: true` keyword option can be provided to reverse
the final result for convenience.

      iex(0)> add_same = fn {x, a}, {y, b} ->
      ...(0)>               cond do
      ...(0)>                 x == y -> {:cont, {x, a + b}}
      ...(0)>                 true   -> {:stop, nil} end end
      ...(0)> E.grouped_reduce(
      ...(0)>   [{:a, 1}, {:a, 2}, {:b, 3}, {:b, 4}], add_same)
      [{:b, 7}, {:a, 3}]

The `grouped_inject` function behaves almost identically to `grouped_reduce`,
however an initial value is provided.

      iex(1)> sub_same = fn {x, a}, {y, b} -> 
      ...(1)>               cond do
      ...(1)>                 x == y -> {:cont, {x, a - b}}
      ...(1)>                 true   -> {:stop, nil}
      ...(1)>               end
      ...(1)>            end
      ...(1)> E.grouped_inject(
      ...(1)> [{:a, 1}, {:b, 2}, {:b, 2}, {:c, 2}, {:c, 1}, {:c, 1}],
      ...(1)>  {:a, 43}, sub_same, reverse: true)
      [a: 42, b: 0, c: 0]


## Tools to facilitate dispatching on keyword parameters, used in contexts like the following

      @defaults [a: 1, b: false] # Keyword or Map
      def some_fun(..., options \ []) # options again can be a Keyword or Map
        {a, b} = tuple_from_params(@defaults, options, [:a, :b])

### Merging defaults and actual parameters

Its most useful feature is that you will get a map whatever the mixtures of maps and keywords the
input was

    iex(0)> merge_params([])
    %{}

    iex(1)> merge_params([a: 1], %{b: 2})
    %{a: 1, b: 2}

    iex(2)> merge_params(%{a: 1}, [a: 2, b: 2])
    %{a: 2, b: 2}

#### Strict merging

_Not implemented yet_

### Extracting params from the merged defaults and actuals

    iex(3)> defaults = [foo: false, depth: 3]
    ...(3)> tuple_from_params(defaults, %{foo: true}, [:foo, :depth])
    {true, 3}

As defaults are required a missing parameter will raise an Error

    iex(4)> try do
    ...(4)>   tuple_from_params([], [foo: 1], [:bar])
    ...(4)> rescue
    ...(4)>   KeyError -> :caught
    ...(4)> end
    :caught

Alternatively on can extract a map

    iex(5)> map_from_params([], [hello: "world"], [:hello])
    %{hello: "world"}



SPDX-License-Identifier: Apache-2.0