Home > Back-end >  Get all keys from nested map
Get all keys from nested map

Time:12-25

  • I did this task using iteraptor libary, how can i do it using only elixir fuctionc not external libraries for example using get_in/2
defmodule MapanalizTest do
  use ExUnit.Case
  doctest Mapanaliz

  test "all_path_list(prev_result, xmap, prev_path)" do
    assert Mapanaliz.all_path_list(%{}, []) == []
    assert Mapanaliz.all_path_list(%{a1: 1}, []) == [[:a1]]
    assert Mapanaliz.all_path_list(%{a1: 1, a2: 1}, []) == [[:a1], [:a2]]
    assert Mapanaliz.all_path_list(%{a1: %{b1: 1}}, []) == [[:a1], [:a1, :b1]]
    assert Mapanaliz.all_path_list(%{a1: 1, a2: %{b1: 1}}) == [[:a1], [:a2], [:a2, :b1]]

    assert Mapanaliz.all_path_list(%{a1: 1, a2: %{a2b1: 1, a2b2: 1}}) ==
             [[:a1], [:a2], [:a2, :a2b1], [:a2, :a2b2]]

    assert Mapanaliz.all_path_list(%{a: %{c: 1, d: 1}, b: %{e: 1}}) ==
             [[:a], [:b], [:a, :c], [:a, :d], [:b, :e]]

    assert Mapanaliz.all_path_list(%{z1: %{y11: 1, y12: 1}, z2: %{y21: %{x221: 1}}}) ==
             [[:z1], [:z2], [:z1, :y11], [:z1, :y12], [:z2, :y21], [:z2, :y21, :x221]]
  end
end
  • SOLUTION I did it like that using Iteraptor module, but how can i do that using only buildin functions
defmodule Mapanaliz do
  def all_path_list(xmap) do
    case xmap do
      %{} -> []
    end

    xmap
    |> Iteraptor.reduce([], fn {k, _}, acc ->
      [Enum.join(k, ", ") | acc]
    end, yield: :all)
    |> :lists.reverse()
end

CodePudding user response:

Rather than a built-in function, this is typically a case for recursion since you want to iterate on a tree:

defmodule Mapanaliz do
  def all_path_list(map, path \\ []) do
    Enum.flat_map(map, fn {key, value} ->
      new_path = path    [key]
      children = if is_map(value), do: all_path_list(value, new_path), else: []
      [new_path | children]
    end)
  end
end

Explanation:

  • we "loop" on the map keys and values
  • if the value is not a map, we just add the current path
  • if the value is a map, we get all its children paths by making a recursive call to all_path_list

There are probably many ways to implement this using recursion. Here I went with Enum.flat_map/2 because we want to merge all paths in a single list, not a list of lists. But you can probably make it more efficient by passing a list accumulator and reversing the list at the end.

  • Related