Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Printing a Tree With Indents. Swift

Implementing a Tree data structure using swift:

class Node {

    var value: String
    var children: [Node] = []
    weak var parent: Node?

    init(_ value: String) {
        self.value = value
    }

    func add(_ child: Node){
        children.append(child)
        child.parent = self
    }

    func printTree() {
        var text = self.value
        if !self.children.isEmpty {
            text += "\n  " + self.children.map{$0.printTree()}.joined(separator: ", ")
        }
        print(text)
    }

}

My goal is to see something like this:

A1
    B2
    C3
        G6
    K0
        H7
            L8
        L9

I know there should be some smart way to insert indents, but I also struggle with 'map'. Compiler gives me "ambiguous reference to member 'map'".

like image 371
Evgeny Avatar asked Jan 29 '23 13:01

Evgeny


1 Answers

If you want to make it pretty, you could do this:

extension Node
{
   func treeLines(_ nodeIndent:String="", _ childIndent:String="") -> [String]
   {
      return [ nodeIndent + value ]
           + children.enumerated().map{ ($0 < children.count-1, $1) }
             .flatMap{ $0 ? $1.treeLines("┣╸","┃ ") : $1.treeLines("┗╸","  ") }
             .map{ childIndent + $0 } 
   }

   func printTree()
   { print(treeLines().joined(separator:"\n")) }
}

a1.printTree()

// A1
// ┣╸B2
// ┣╸C3
// ┃ ┗╸G6
// ┗╸K0
//   ┣╸H7
//   ┃ ┗╸L8
//   ┗╸L9

You could also generalize it into a print function for any tree structure that will let you choose what to print for each node:

func printTree<T>(_ node:T, _ nodeInfo:@escaping (T)->(String,[T]) ) 
{
  func lines(_ aNode:T, _ nodeIndent:String="", _ childIndent:String="") -> [String]
  {
    let (label,children) = nodeInfo(aNode)
    return [ nodeIndent + label]
         + children.enumerated().map{ ($0 < children.count-1, $1) }
           .flatMap{ $0 ? lines($1,"┣╸","┃ ") :lines($1,"┗╸","  ") }
           .map{ childIndent + $0 }
  }
  print( lines(node).joined(separator:"\n") )
}

// print a root node providing a capture to obtain the node's label
// and its array of children

printTree(a1){ ($0.value,$0.children) }

// works for any tree structure.  for example, views :

printTree(view){( "\(type(of:$0)) \($0.frame)", $0.subviews )} 
like image 168
Alain T. Avatar answered Feb 05 '23 16:02

Alain T.