# `Cldr.Map`
[🔗](https://github.com/elixir-cldr/cldr_utils/blob/v2.29.6/lib/cldr/utils/map.ex#L1)

Functions for transforming maps, keys and values.

# `atomize_keys`

Transforms a `map`'s `String.t` keys to `atom()` keys.

## Arguments

* `map` is any `t:map/0`

* `options` is a keyword list of options passed
  to `deep_map/3`. One additional option apples
  to this function directly:

  * `:only_existing` which is set to `true` will
    only convert the binary value to an atom if the atom
    already exists.  The default is `false`.

## Example

    iex> Cldr.Map.atomize_keys %{"a" => %{"b" => %{1 => "c"}}}
    %{a: %{b: %{1 => "c"}}}

# `atomize_values`

Transforms a `map`'s `String.t` values to `atom()` values.

## Arguments

* `map` is any `t:map/0`

* `options` is a keyword list of options passed
  to `deep_map/3`. One additional option apples
  to this function directly:

  * `:only_existing` which is set to `true` will
    only convert the binary value to an atom if the atom
    already exists.  The default is `false`.

## Examples

    iex> Cldr.Map.atomize_values %{"a" => %{"b" => %{1 => "c"}}}
    %{"a" => %{"b" => %{1 => :c}}}

# `combine_list_resolver`

# `deep_map`

```elixir
@spec deep_map(
  map() | list(),
  function :: function() | {function(), function()},
  options :: list()
) :: map() | list()
```

Recursively traverse a map and invoke a function
that transforms the mapfor each key/value pair.

## Arguments

* `map` is any `t:map/0`

* `function` is a `1-arity` function or function reference that
  is called for each key/value pair of the provided map. It can
  also be a 2-tuple of the form `{key_function, value_function}`

  * In the case where `function` is a single function it will be
    called with the 2-tuple argument `{key, value}`

  * In the case where function is of the form `{key_function, value_function}`
    the `key_function` will be called with the argument `key` and the value
    function will be called with the argument `value`

* `options` is a keyword list of options. The default is
  `[level: 1..1000000, filter: [], reject: [], skip: [], only: [], except: []]`

## Options

* `:level` indicates the starting (and optionally ending) levels of
  the map at which the `function` is executed. This can
  be an integer representing one `level` or a range
  indicating a range of levels. The default is `1..1000000`

* `:only` is a term or list of terms or a `check function`. If it is a term
  or list of terms, the `function` is only called if the `key` of the
  map is equal to the term or in the list of terms. If `:only` is a
  `check function` then the `check function` is passed the `{k, v}` of
  the current branch in the `map`. It is expected to return a `truthy`
  value that if `true` signals that the argument `function` will be executed.

* `:except` is a term or list of terms or a `check function`. If it is a term
  or list of terms, the `function` is only called if the `key` of the
  map is not equal to the term or not in the list of terms. If `:except` is a
  `check function` then the `check function` is passed the `{k, v}` of
  the current branch in the `map`. It is expected to return a `truthy`
  value that if `true` signals that the argument `function` will not be executed.

* `:filter` is a term or list of terms or a `check function`. If the
  `key` currently being processed equals the term (or is in the list of
  terms, or the `check_function` returns a truthy value) then this branch
  of the map is processed by `function` and its output is included in the result.

* `:reject` is a term or list of terms or a `check function`. If the
  `key` currently being processed equals the term (or is in the list of
  terms, or the `check_function` returns a truthy value) then this branch
  of the map is omitted from the mapped output.

* `:skip` is a term or list of terms or a `check function`. If the
  `key` currently being processed equals the term (or is in the list of
  terms, or the `check_function` returns a truthy value) then this branch
  of the map is *not* processed by `function` but it is included in
  the mapped result.

## Notes

* `:only` and `:except` operate on individual keys whereas `:filter`
  and `:filter` and `:reject` operator on *entire branches* of a map

* If both the options `:only` and `:except` are provided then the `function`
  is called only when a `term` meets both criteria. That means that `:except`
  has priority over `:only`.

* If both the options `:filter` and `:reject` are provided then `:reject`
  has priority over `:filter`.

## Returns

* The `map` transformed by the recursive application of
  `function`

## Examples

    iex> map = %{a: :a, b: %{c: :c}}
    iex> fun = fn
    ...>   {k, v} when is_atom(k) -> {Atom.to_string(k), v}
    ...>   other -> other
    ...> end
    iex> Cldr.Map.deep_map map, fun
    %{"a" => :a, "b" => %{"c" => :c}}
    iex> map = %{a: :a, b: %{c: :c}}
    iex> Cldr.Map.deep_map map, fun, only: :c
    %{a: :a, b: %{"c" => :c}}
    iex> Cldr.Map.deep_map map, fun, except: [:a, :b]
    %{a: :a, b: %{"c" => :c}}
    iex> Cldr.Map.deep_map map, fun, level: 2
    %{a: :a, b: %{"c" => :c}}

# `deep_merge`

Deep merge two maps

* `left` is any `t:map/0`

* `right` is any `t:map/0`

## Examples

    iex> Cldr.Map.deep_merge %{a: "a", b: "b"}, %{c: "c", d: "d"}
    %{a: "a", b: "b", c: "c", d: "d"}

    iex> Cldr.Map.deep_merge %{a: "a", b: "b"}, %{c: "c", d: "d", a: "aa"}
    %{a: "aa", b: "b", c: "c", d: "d"}

# `delete_in`

Delete all members of a map that have a
key in the list of keys

## Examples

    iex> Cldr.Map.delete_in %{a: "a", b: "b"}, [:a]
    %{b: "b"}

# `extract_strings`

Extract strings from a map or list

Recursively process the map or list
and extract string values from maps
and string elements from lists

# `floatize_keys`

Transforms a `map`'s `String.t` keys to `Float.t` values.

## Arguments

* `map` is any `t:map/0`

* `options` is a keyword list of options passed
  to `deep_map/3`

The map key is converted to a `float` from
a `String.t` only when the key is comprised of
a valid float form.

Keys which cannot be converted to a `float`
are returned unchanged.

## Examples

    iex> Cldr.Map.floatize_keys %{a: %{"1.0" => "value"}}
    %{a: %{1.0 => "value"}}

    iex> Cldr.Map.floatize_keys %{a: %{"1" => "value"}}
    %{a: %{1.0 => "value"}}

# `floatize_values`

Transforms a `map`'s `String.t` values to `Float.t` values.

## Arguments

* `map` is any `t:map/0`

* `options` is a keyword list of options passed
  to `deep_map/3`

The map value is converted to a `float` from
a `String.t` only when the
value is comprised of a valid float form.

Values which cannot be converted to a `float`
are returned unchanged.

## Examples

    iex> Cldr.Map.floatize_values %{a: %{b: "1.0"}}
    %{a: %{b: 1.0}}

    iex> Cldr.Map.floatize_values %{a: %{b: "1"}}
    %{a: %{b: 1.0}}

# `from_keyword`

# `identity`

Returns am argument unchanged.

Useful when a `noop` function is required.

# `integerize_keys`

Transforms a `map`'s `String.t` keys to `Integer.t` keys.

## Arguments

* `map` is any `t:map/0`

* `options` is a keyword list of options passed
  to `deep_map/3`

The map key is converted to an `integer` from
either an `atom` or `String.t` only when the
key is comprised of `integer` digits.

Keys which cannot be converted to an `integer`
are returned unchanged.

## Example

    iex> Cldr.Map.integerize_keys %{a: %{"1" => "value"}}
    %{a: %{1 => "value"}}

# `integerize_values`

Transforms a `map`'s `String.t` values to `Integer.t` values.

## Arguments

* `map` is any `t:map/0`

* `options` is a keyword list of options passed
  to `deep_map/3`

The map value is converted to an `integer` from
either an `atom` or `String.t` only when the
value is comprised of `integer` digits.

Keys which cannot be converted to an integer
are returned unchanged.

## Example

    iex> Cldr.Map.integerize_values %{a: %{b: "1"}}
    %{a: %{b: 1}}

# `invert`

Invert a map

Requires that the map is a simple map of
keys and a list of values or a single
non-map value

## Options

* `:duplicates` which determines how duplicate values
  are handled:
  * `nil` or `false` which is the default and means only
    one value is kept. `Map.new/1` is used meanng the
    selected value is non-deterministic.
  * `:keep` meaning duplicate values are returned in a list
  * `:shortest` means the shortest duplicate is kept.
    This operates on string or atom values.
  * `:longest` means the shortest duplicate is kept.
    This operates on string or atom values.

# `merge_map_list`

Returns the result of deep merging a list of maps

## Examples

    iex> Cldr.Map.merge_map_list [%{a: "a", b: "b"}, %{c: "c", d: "d"}]
    %{a: "a", b: "b", c: "c", d: "d"}

# `process_type`

# `prune`

Prune a potentially deeply nested map of some of
its branches

# `remove_leading_underscores`

Removes any leading underscores from `map`
`String.t` keys.

* `map` is any `t:map/0`

* `options` is a keyword list of options passed
  to `deep_map/3`

## Examples

    iex> Cldr.Map.remove_leading_underscores %{"a" => %{"_b" => "b"}}
    %{"a" => %{"b" => "b"}}

# `rename_keys`

Rename map keys from `from` to `to`

* `map` is any `t:map/0`

* `from` is any value map key

* `to` is any valid map key

* `options` is a keyword list of options passed
  to `deep_map/3`

## Example

    iex> Cldr.Map.rename_keys %{"a" => %{"this_one" => "value"}}, "this_one", "that_one"
    %{"a" => %{"that_one" => "value"}}

# `stringify_keys`

Transforms a `map`'s `atom()` keys to `String.t` keys.

## Arguments

* `map` is any `t:map/0`

* `options` is a keyword list of options passed
  to `deep_map/3`

## Example

    iex> Cldr.Map.stringify_keys %{a: %{"1" => "value"}}
    %{"a" => %{"1" => "value"}}

# `stringify_values`

Transforms a `map`'s `atom()` keys to `String.t` keys.

## Arguments

* `map` is any `t:map/0`

* `options` is a keyword list of options passed
  to `deep_map/3`

## Example

    iex> Cldr.Map.stringify_values %{a: %{"1" => :value}}
    %{a: %{"1" => "value"}}

# `underscore`

```elixir
@spec underscore(string :: String.t() | atom()) :: String.t()
```

Convert a camelCase string or atom to a snake_case

* `string` is a `String.t` or `atom()` to be
  transformed

This is the code of Macro.underscore with modifications.
The change is to cater for strings in the format:

  This_That

which in Macro.underscore gets formatted as

  this__that (note the double underscore)

when we actually want

  that_that

## Examples

    iex> Cldr.Map.underscore "thisThat"
    "this_that"

    iex> Cldr.Map.underscore "This_That"
    "this_that"

# `underscore_keys`

Convert map `String.t` keys from `camelCase` to `snake_case`

* `map` is any `t:map/0`

* `options` is a keyword list of options passed
  to `deep_map/3`

## Example

    iex> Cldr.Map.underscore_keys %{"a" => %{"thisOne" => "value"}}
    %{"a" => %{"this_one" => "value"}}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
