ramziabbyad1

ramziabbyad1

Pattern matching nested tuples

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

Marked As Solved

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

Also Liked

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

Last Post!

ramziabbyad1

ramziabbyad1

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

Where Next?

Popular in Questions Top

vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
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
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
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

Other popular topics Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42533 114
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement