Skip to content

Instantly share code, notes, and snippets.

@IvanIvanoff
Last active June 5, 2019 13:51
Show Gist options
  • Save IvanIvanoff/b4f58f35ccba003e752a6076999628e7 to your computer and use it in GitHub Desktop.
Save IvanIvanoff/b4f58f35ccba003e752a6076999628e7 to your computer and use it in GitHub Desktop.
Search where is located a key-value pair in deeply nested structs
defmodule MapUtils do
def find_pair_path(map, key, value) when is_map(map) do
do_find_pair_path(map, key, value, [])
|> Enum.map(&(&1 |> List.flatten() |> Enum.reverse()))
|> Enum.reject(&(&1 == nil || &1 == []))
end
defp do_find_pair_path(map, key, value, path) when is_map(map) do
keys = Map.keys(map)
if key in keys and Map.get(map, key) == value do
[key | path]
else
Enum.map(keys, fn subkey ->
Map.get(map, subkey)
|> do_find_pair_path(key, value, [subkey | path])
end)
end
end
defp do_find_pair_path(list, key, value, path) when is_list(list) do
Enum.with_index(list)
|> Enum.map(fn {elem, index} ->
do_find_pair_path(elem, key, value, [{:at, index} | path])
end)
end
defp do_find_pair_path(_, _, _, _), do: []
end
# [[:a, :b, "name"]]
%{a: %{b: %{"name" => "ivan"}}} |> MapUtils.find_pair_path("name", "ivan")
# [[:a, :b, {:at, 0}, "name"]]
%{a: %{b: [%{"name" => "ivan"}]}} |> MapUtils.find_pair_path("name", "ivan")
# [[:a, {:at, 0}, :b, {:at, 0}, "name"]]
%{a: [%{b: [%{"name" => "ivan"}]}]} |> MapUtils.find_pair_path("name", "ivan")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment