Need advise to update nested list 3-level

It looks like you might be doing a lot of data access.

You might get a huge boost in simplicity and performance by using maps instead of lists.
If you were willing to separate storing and sorting of children, you could store a map of children and an order list that has ordered child ids:

elements = %{
  children: %{
    "62197198-e3a1-46de-8f18-f2c6843f646f" => %{
      children: %{
        "b2a6b171-26e1-4e8a-8cd3-c41f388de6e8" => %{
          children: [],
          class: ["text-black", "w-full", "p-2"],
          id: "b2a6b171-26e1-4e8a-8cd3-c41f388de6e8",
          # index: 1,
          parent: "section",
          parent_id: "62197198-e3a1-46de-8f18-f2c6843f646f",
          type: "text"
        },
        "c9ea0fff-1ee0-407e-8b2a-64afc954c40b" => %{
          children: [],
          class: ["text-black", "w-full", "p-2"],
          id: "c9ea0fff-1ee0-407e-8b2a-64afc954c40b",
          # index: 0,
          parent: "section",
          parent_id: "62197198-e3a1-46de-8f18-f2c6843f646f",
          type: "text"
        }
      },
      class: ["flex", "flex-col", "justify-between", "items-stretch",
       "min-h-[200px]", "w-full", "border", "border-dashed", "border-gray-400",
       "p-1"],
      id: "62197198-e3a1-46de-8f18-f2c6843f646f",
      # index: 0,
      order: ["c9ea0fff-1ee0-407e-8b2a-64afc954c40b",
       "b2a6b171-26e1-4e8a-8cd3-c41f388de6e8"],
      parent: "layout",
      parent_id: "64a2c3f2-d71f-464a-8318-be072d7b6624",
      type: "section"
    }
  },
  order: ["62197198-e3a1-46de-8f18-f2c6843f646f"],
  class: ["flex", "flex-row", "justify-start", "items-center", "w-full",
   "space-x-3", "px-3", "py-10"],
  id: "64a2c3f2-d71f-464a-8318-be072d7b6624",
  # index: 0,
  order: "62197198-e3a1-46de-8f18-f2c6843f646f",
  parent: "dragLocation",
  parent_id: "dragLocation",
  type: "layout"
}

Once you do that, you can use @codeanpeace’s Access module functions at a cost of O(n) instead of O(n^3):

Look up would be:

def find(elements, id, parent_id, layout_id) do
  get_in(elements, [:children, layout_id,:children, parent_id, :children, id])
end

Updating an element

def add_tag(elements, id, parent_id, layout_id, tag, type) when type in @elements do
  update_in(elements, [:children, layout_id,:children, parent_id, :children, id], fn selected_element ->
      if selected_element.type == type do
        Map.merge(selected_element, %{tag: tag})
      end
  end)
end

Removing an element:

def delete(elements, id, parent_id, layout_id) do
  # Remove the child
  {_,elements} = pop_in(elements,  [:children, layout_id,:children, parent_id, :children, id])
  # Remove it from the order
  elements = update_in(elements,  [:children, layout_id,:children, parent_id, :order], fn order ->
    Enum.reject(order, &(&1 == id))
  end)
  elements
end

Adding is similar to deleting

3 Likes