How to check if the key exists in a deeply nested Map in Elixir

Viewed 1649

I have a map object I need to check if it contain a given key. I tried like below but it always return false. Also how to pull value on inside map replyMessage,

map=%{
  Envelope: %{
    Body: %{
      replyMessage: %{
        cc: %{
          "amount" => "100.00",
          "reasonCode" => "100",
        },
        decision: "ACCEPT",
        invalidField: nil,
        purchaseTotals: %{"currency" => "CAD"},
        reasonCode: "100",

      }
    }
  }
}
Map.has_key?(map,  %{Envelope: %{Body: %{replyMessage: replyMessage}}})= false
1 Answers

You have two possibilities: Kernel.match?/2 to check whether the key exists and/or Kernel.get_in/2 to deeply retrieve the value.

iex|1 ▶ match?(%{Envelope: %{Body: %{replyMessage: _}}}, map)      
#⇒ true

iex|2 ▶ get_in(map, [:Envelope, :Body, :replyMessage])
#⇒ %{
#   cc: %{"amount" => "100.00", "reasonCode" => "100"},
#   decision: "ACCEPT",
#   invalidField: nil,
#   purchaseTotals: %{"currency" => "CAD"},
#   reasonCode: "100"
# }

Beware of Kernel.get_in/2 would return nil if the key exists, but has nil value, as well as if the key does not exist.


Map.has_key?/2 is not recursive by any mean, it works with the keys of the map, passed as an argument; that said, the first level only.


Sidenote: one might easily build a recursive solution themselves, based on Map.has_key/2

defmodule Deep do
  @spec has_key?(map :: map(), keys :: [atom()]) :: boolean()
  def has_key?(map, _) when not is_map(map), do: false
  def has_key?(map, [key]), do: Map.has_key?(map, key)
  def has_key?(map, [key|tail]),
    do: Map.has_key?(map, key) and has_key?(map[key], tail)
end

Deep.has_key?(map, [:Envelope, :Body, :replyMessage])
#⇒ true
Related