Convert multiple map values conditionally

I have a function called deep_map that I use in several different projects to simplify certain classes of map operations. On top of that I have other functions like atomize_keys/3 and so on. It might be useful (or it might be not :slight_smile: )

Summary

Recursively traverse a map and invoke a function
that transforms the map for 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 []

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..#{@max_level}
  • :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.

Notes

If both the options :only and :except are provided then the function
is called only when a term meets both criteria.

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}}