ramziabbyad1

ramziabbyad1

This is listed as one of the “Hard” problem in 7 languages 7 weeks book. "Represent a tree of sentences as tuples. Traverse the tree, presenting an indented list.

I think I have solved it, but I’m wondering if there is a cleaner way to do this without all the conditionals. Thanks!

Book example:

{“See spot run.”, {“See spot sit”, “See spot run”}} will print

See spot run.
See spot sit
See spot run

And my example:

TreeRecurse.print_tree({"See spot.", {{"See spot sit.", {"Sitting down.", {"Run spot", {"Runnn!"}}}}, "See spot run."}}, "")

will produce the output:

See spot.
See spot sit.
Sitting down.
Run spot
Runnn!
See spot run.

defmodule TreeRecurse do
  def print_tree({leaf}, indent), do: IO.puts "#{indent}#{leaf}"

  def print_tree({root,{lone}},indent) do
    IO.puts "#{indent}#{root}"

    if is_tuple(lone) do
      print_tree(lone, indent <> " ")
    else
      print_tree({lone}, indent <> " ")
    end

  end

  def print_tree({root,{left,right}},indent) do

    IO.puts "#{indent}#{root}"

    if is_tuple(left) do
      print_tree(left, indent <> " ")
    else
      print_tree({left}, indent <> " ")
    end

    if is_tuple(right) do
      print_tree(right, indent <> " ")
    else
      print_tree({right}, indent <> " ")
    end

  end

end

Showing Posts 1 to 4

zevv

zevv

This is a nice fit for a case with some guards:

  def print_tree2(t, indent) do       
    case t do
      {a, b} when is_binary(a) -> 
        IO.puts "#{indent}#{a}"   
        print_tree2(b, indent <> " ") 
      {a, b} when is_binary(b) ->
        print_tree2(a, indent <> " ") 
        IO.puts "#{indent}#{b}"
      {a} when is_binary(a) ->
        IO.puts "#{indent}#{a}"
    end 
  end
mudasobwa

mudasobwa

Creator of Cure

I always prefer function clauses instead of conditionals (if/2, case/2, cond/1) whenever possible.

defmodule TreeRecurse do
  @indent 2
  
  def print_tree(tree, indent \\ 0, acc \\ []) do
    tree
    |> traverse_tree(indent, acc)
    |> Enum.join("\n")
    |> IO.puts()
  end
  
  defp traverse_tree(leaf, indent, acc) when is_binary(leaf),
    do: [indented(leaf, indent) | acc]
 
  defp traverse_tree({leaf}, indent, acc),
    do: traverse_tree(leaf, indent, acc)

  defp traverse_tree({head, tail}, indent, acc) when is_binary(head) and is_binary(tail),
    do: [indented(head, indent), indented(tail, indent) | acc]
  
  defp traverse_tree({head, tail}, indent, acc) when is_binary(head),
    do: [indented(head, indent) | traverse_tree(tail, indent + 1, acc)] ++ acc
  
  defp traverse_tree({head, tail}, indent, acc) when is_binary(tail),
    do: traverse_tree(head, indent + 1, acc) ++ [indented(tail, indent) | acc]
  
  defp traverse_tree({head, tail}, indent, acc),
    do: traverse_tree(head, indent + 1, acc) ++ traverse_tree(tail, indent + 1, acc) ++ acc
  
  defp indented(input, indent) when is_number(indent),
    do: ' ' |> List.duplicate(indent * @indent) |> to_string() |> Kernel.<>(input) 
end
ramziabbyad1

ramziabbyad1 OP

Nice, I will have to digest this a bit. It is very clean, but also somewhat verbose from my perspective. More of an engineering solution. Thanks!

ramziabbyad1

ramziabbyad1 OP

Love it, thanks! I figured out that in the end I would need to pattern match a string, so this is exactly what I was looking for. I ended up pattern match “” <> string, but from what I read about unicode strings is_binary or a binary pattern match may be more robust. See my updated solution:

  def print_tree("" <> string, indent), do: IO.puts "#{indent}#{string}"
  def print_tree({leaf}, indent), do: IO.puts "#{indent}#{leaf}"
  def print_tree({root,{lone}},indent) do
    IO.puts "#{indent}#{root}"
    print_tree(lone, indent <> " ")
  end
  def print_tree({root,{left,right}},indent) do
    IO.puts "#{indent}#{root}"
    print_tree(left, indent <> " ")
    print_tree(right, indent <> " ")
  end

— All posts loaded —

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
achenet
Hello, I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind. However, when I launch mix phx.server, I get an error...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
Cxx-mlr
I’m working on a small exercise involving update_in/3, and I came up with this solution: data = %{ name: "Periodic Table", category:...
New
ChrisAmelia
I’ve got trouble wrapping my head around the order in which functions are called in this snippet (from Phoenix’s authentication): toke...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews