Search code examples
swifttreetrie

Create a Trie from an array of strings using in swift with certain Constraint


create a Trie from an array of strings using in swift

The concept is : you have given an array of strings like :

# The input will be always in the below format "x1>x2>x3...>xn=Integer" else it is invalid input #

private let input = [
    "a>b>c=1",
    "a>b>c=2",
    "d>c=3",
    "f>e=10",
    "a>b=20",  // Invalid, Node(b) has Child, cannot insert the value
    "a>b>c>d=11", // Invalid , Node(c) has value, but trying to insert child, invalid case
    "a>a>a=100"
]

(1). Let's consider the first input : "a>b>c=1" which consists of 2 parts based on "=" operator "a>b>c" and "1".

The first part is used for tree hierarchy where x>y means x is parent of y and the value "1" will be child of last node. It creates a tree like below for the first time as tree is empty at beginning.

( Root ) --> ("a") --> ("b") --> ("c") --> [1]

(2) Consider 2nd input : "a>b>c=2". Divide the input into 2 parts "a>b>c" and "2" based on "=". While processing "a>b>c", it's simply traversing because node("a"), node("b"), node("c") are in correct hierarchy and update the value node by appending value=2 so value([1,2]). Tree looks like :

( Root ) --> ("a") --> ("b") --> ("c") --> [1,2]

(3) Considering "d>c=3", the tree looks like :

( Root ) --> ("a") --> ("b") --> ("c") --> [1,2]
   |
   --> ("d") --> ("c") --> [3]

(4) Considering "a>b=20" input produce an ERROR because node("b") has a child node("c") so you cannot insert value([20]) for node("b"), So, don't process for this input. (no modification in tree)

(5) considering "a>b>c>d=11" input, produce an ERROR because node("c") has a Value([1,2]) child, you cannot add a node("d") as child of node("c"), So, don't process for this input. (no modification in tree)

You have to construct the Trie like below considering the above input.

 {
        "a" : { "b" : { "c" : [1,2] },
                "a" : { "a" : [100] }
              },
        "d" : { "c" : [3]  },
        "f" : { "e" : [10] }
 }

Solution

  • Solution :

    import Foundation
    
    // Element must have either value or childDictionary, not at the same time
    
    class Element {
      var value : [Int]?
      var childDictionary : Dictionary<String, Element>?
    
      init(value : [Int]?, childKey : String?, childValue : Element? ) {
         self.value = value
         self.childDictionary = nil
    
         if let childKey = childKey, let childValue = childValue {
             var dict = Dictionary<String, Element>()
             dict[childKey] = childValue
             childDictionary = dict
         }
      }
    }
    
    class JsonCreator {
    
    private var root : Element?
    
    private let jsonInput = [
        "a>b>c=1",
        "a>b>c=2",
        "d>c=3",
        "f>e=10",
        "a>b=20",  // Invalid, Node(b) has Child, cannot insert the value
        "a>b>c>d=11" // Invalid , Node(c) has value, but trying to insert child, invalid case
    ]
    
    public func create() {
        root = Element(value: nil, childKey: nil, childValue: nil) // root one
        createJSON(input: jsonInput)
        print("\n\n Output \n\n")
        printJson(root: root)
    }
    
    private func createJSON(input : [String]) {
    
        let rootJson = root
    
        for each in input {
            print("\n---------------------- New Input ----------------------\n")
            // split the string into 2 parts
            let parts = each.components(separatedBy: "=")
    
            if parts.count > 1 { // go through the hierarchy
    
                let literals = parts[0].filter{ $0 != ">" }
                print(literals)
    
                var traversal = rootJson
                var char : Character!
                var hasError = false
    
                // literals
                for i in 0..<literals.count {
                    char = literals[literals.index(literals.startIndex, offsetBy: i)]
                    print("Processing : \(char!)")
    
                    if let _ = traversal?.value {
                        print("ERROR : Node has value, but trying to insert child, invalid case")
                        hasError = true
                        break
    
                    } else if traversal?.childDictionary == nil {
                        print("Child is Empty : Do Insertion")
                        let node = Element(value: nil, childKey:nil , childValue: nil)
                        var dict = Dictionary<String, Element>()
                        dict[String(char)] = node
                        traversal?.childDictionary = dict
                        traversal = node // update traversal
    
                    } else if let isChildPresent = traversal?.childDictionary?.keys.contains(String(char)), !isChildPresent {
                        print("Child is not Empty, but not present in the hierary, Do Insertion")
                        let node = Element(value: nil, childKey:nil , childValue: nil)
                        traversal?.childDictionary?[String(char)] = node
                        traversal = node // update traversal
    
                    } else {
                        print("Child is not Empty, but present in the hierary: NO Insertion, only traverse ")
                        if let updateTraversal =  traversal?.childDictionary?[String(char)] {
                            traversal = updateTraversal // update traversal
                        }
                    }
                }
    
                // Value
                if let _ = char, let val = Int(parts[1]), !hasError {
                    print("value : \(val)")
    
                    if let _ = traversal?.childDictionary {
                        print("ERROR : Node has Child, cannot insert the value")
                    } else {
                        print("Append the value")
                        if let _ = traversal?.value {
                            traversal?.value?.append(val)
                        } else {
                            traversal?.value = [val]
                        }
                    }
                }
                root = rootJson // update root for every input
            }
        }
    }
    
    private func printJson(root : Element?) {
        if let childDictionary = root?.childDictionary {
            for each in childDictionary {
                print("{ \(each.key) : ", terminator : "")
                printJson(root: each.value)
                print("}")
            }
        }
    
        if let values = root?.value {
            print("\(values)")
        }
     }
    }
    
    let jsonCreateObj = JsonCreator()
    jsonCreateObj.create()
    

    Output :

         ---------------------- New Input ----------------------
    
         abc
         Processing : a
         Child is Empty : Do Insertion
         Processing : b
         Child is Empty : Do Insertion
         Processing : c
         Child is Empty : Do Insertion
         value : 1
         Append the value
    
         ---------------------- New Input ----------------------
    
         abc
         Processing : a
         Child is not Empty, but present in the hierary: NO Insertion, only traverse 
         Processing : b
         Child is not Empty, but present in the hierary: NO Insertion, only traverse 
         Processing : c
         Child is not Empty, but present in the hierary: NO Insertion, only traverse 
         value : 2
         Append the value
    
        ---------------------- New Input ----------------------
    
        dc
        Processing : d
        Child is not Empty, but not present in the hierary, Do Insertion
        Processing : c
        Child is Empty : Do Insertion
        value : 3
        Append the value
    
        ---------------------- New Input ----------------------
    
        fe
        Processing : f
        Child is not Empty, but not present in the hierary, Do Insertion
        Processing : e
        Child is Empty : Do Insertion
        value : 10
        Append the value
    
        ---------------------- New Input ----------------------
    
        ab
        Processing : a
        Child is not Empty, but present in the hierary: NO Insertion, only traverse 
        Processing : b
        Child is not Empty, but present in the hierary: NO Insertion, only traverse 
       value : 20
       ERROR : Node has Child, cannot insert the value
    
       ---------------------- New Input ----------------------
    
       abcd
       Processing : a
       Child is not Empty, but present in the hierary: NO Insertion, only traverse 
    
       Processing : b
       Child is not Empty, but present in the hierary: NO Insertion, only traverse 
    
       Processing : c
       Child is not Empty, but present in the hierary: NO Insertion, only traverse 
    
       Processing : d
       ERROR : Node has value, but trying to insert child, invalid case
    
    
       Output 
    
    
       { d : { c : [3]
       }
       }
       { a : { b : { c : [1, 2]
       }
       }
       }
       { f : { e : [10]
       }
       }