Most efficient way to retrieve multiple values from nested map

Sure thing! Look that in original version I’m using map as a root of input, but in code you would find that also list is supported. The proper info for this data would be:

data = %{
  gps: %{
    lat: 48.857144,
    lon: 2.340242,
    altitude: 35.0
  },
  macaddress: "B8:C0:78:CD:12:AB"
}

info = [%{gps: [:lat, :lon]}, :macaddress]
iex> Example.sample(data, info)

However I found one thing. In original code list part is not best. I would rewrite it to tuple instead, for example:

defmodule Example do
  def sample(acc \\ %{}, data, info)

  # in case nested value does not exists
  def sample(acc, nil, _info), do: acc

  # instead of above you may want to use another code
  # as it would place a nil value for each nested info who does not exists in data you passed
  # 
  # def sample(acc, nil, info) when is_atom(info), do: Map.put(acc, info, nil)
  # def sample(acc, nil, info) when is_list(info), do: Enum.reduce(info, acc, &sample(&2, nil, &1))
  # 
  # def sample(acc, nil, info) when is_map(info) do
  #   Enum.reduce(info, acc, &sample(&2, nil, elem(&1, 1)))
  # end

  # when we want to fetch nested fields and root fields at the same time
  # we are passing {nested_fields_map_info, root_fields_list_info}
  def sample(acc, data, {map_info, list_info}) when is_map(map_info) and is_list(list_info) do
    acc |> sample(data, map_info) |> sample(data, list_info)
  end

  # when we need to fetch a flat list of fields
  def sample(acc, data, info) when is_list(info) do
    Enum.reduce(info, acc, &Map.put(&2, &1, data[&1]))
  end

  # here we are reducing info map over our acc
  # which means all nested fields logic goes here
  def sample(acc, data, info) when is_map(info) do
    Enum.reduce(info, acc, fn {info_key, info_value}, acc ->
      sample(acc, data, info_key, info_value)
    end)
  end

  # this clause would match if we want to fetch just one nested field
  # %{nested: :field}
  defp sample(acc, data, info_key, info_value) when is_atom(info_value) do
    Map.put(acc, info_value, get_in(data, [info_key, info_value]))
  end

  # in any other case call the same logic, but with nested data and info
  # %{nested: [:field1, :field2, …]}
  # or
  # %{nested: %{nested_level2: …}}
  # or
  # %{nested: {%{nested_level2: …}, [:field]}
  defp sample(acc, data, info_key, info_value), do: sample(acc, data[info_key], info_value)
end

data = %{
  gps: %{
    lat: 48.857144,
    lon: 2.340242,
    altitude: 35.0
  },
  metadata: %{
    payload: %{
      content: "1aff4c0002154a080bff4c0010774058308876aa3a29",
      scantime: 1_644_362_438
    },
    macaddress: "B8:C0:78:CD:12:AB",
    receivetime: 1_663_000_169,
    tags: "v1.2,test.app"
  }
}

info = %{gps: [:lat, :lon], metadata: {%{payload: :scantime}, [:receivetime]}}
iex> Example.sample(data, info)

data2 = %{
  gps: %{
    lat: 48.857144,
    lon: 2.340242,
    altitude: 35.0
  },
  macaddress: "B8:C0:78:CD:12:AB"
}

iex> Example.sample(data2, {%{gps: [:lat, :lon]}, [:macaddress]})

This way instead of [%{nested: …}, :field1, …] we have {%{nested: …}, [:field1, …]} which separates nested map info from root list info. This way we no longer need to call Enum.groiup_by/2.