dredison

dredison

How to recurse and build a key to access a child node

Hi,

So I’m new to Elixir and I’m struggling with a recursion question. I have a tree structure (of structs, with ordered lists of children), where each node has a single parent and many children. it can be nested to an arbitrary depth.

tree = %{
    id: "a",
    children: [
        %{ 
          id: "one",
          children: [
            %{ 
              id: "two"
            }
          ]
        },
        %{ 
          id: "three",
          children: [
            %{ 
              id: "four"
            },
            %{ 
              id: "five"
            },
          ]
        },
    ]
}

I’m trying to write a recursive function that will build an access key to a given node, identified by its ID.

Tree.path_to(tree, id, path \\ [])
``

So for example id "five", would return the following, which I can then use with the kernel's get_in and update_in functions.

[:children, Acess.to(1), :children, Access.to(1)]


I'm just too new to Elixir (and functional programming in general) to work it out so any help would be appreciated!

Marked As Solved

aziz

aziz

Hi dredison! Was going to give you a partial solution for your learning but I pretty much solved it:

# When parameters appear multiple times they are checked for equality.
def path_to(%{id: id}, id), do: []

def path_to(%{children: [_ | _] = children}, id) do
  case subpath_to(children, id) do
    {idx, path} -> [:children, idx | path]
    _ -> nil
  end
end

def path_to(_, _), do: nil

def subpath_to(children, id) do
  Enum.reduce_while(children, 0, fn child, idx ->
    path = path_to(child, id)
    if path, do: {:halt, {idx, path}}, else: {:cont, idx + 1}
  end)
end

You still have to do something to get the desired format. :slightly_smiling_face:

Tip: When writing recursive functions it always helps to handle the basic cases first and to make sure that there’s a terminating clause. Then you build on that and work your way down to the nested structures and see if you can use the functions that handle the basic cases.

Also Liked

dredison

dredison

Hey Aziz,

Amazing, thank you. Works like a charm. It’s also pointed me towards a better understanding of pattern matching and function arguments. Thanks again.

Where Next?

Popular in Questions Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
Werner
Hi, I’m using Ubuntu 18.04 and after updating to OTP-24.0 yesterday i have this warning when I run “mix local.hex”: 14:57:30.512 [warn] ...
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
Fl4m3Ph03n1x
Background Let’s assume I have a typical GenServer that receives messages as requests, does some operation in a DB and returns responses....
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
Mooodi
Given a string, how can I get access to its character by index? Enum.at("my_string", 2) doesn't work. Or rather, not char, but a substr...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
AstonJ
You’re a programmer, so you don’t need spoon feeding with the conventional drivel about “this is an integer.” No. You need to know what’s...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement