Home > database >  Unable to process recursive structure
Unable to process recursive structure

Time:08-06

I have a recursive JSON structure that I want to store as a series of maps with keys. The structure is a series of flows and subflows which can reference each other. Here is a declaration of the types: Plase note that the issue is not with maps. I use use and store objects in the application in several places as I am using a typescript version that is able to store objects. The algorithm is faulty and that's what is the issue

    type Flow = {
       flowId: number,
       subFlows?: Array<SubFlow>
    } 

    type SubFlow = {
      subFlowId: number,
      flow?: Flow,
    }

    type FlowGroup = {
        flows:Map<number,Flow>,
        subFlows:Map<number,Flow>
    }

Ultimately, the goal is to store the flow in a flowgroup structure with flowIds as keys And here is a sample of the JSON:

             {
               "flowId": 90112,
               "subFlows": [
                {
                "subFlowId": 52820,
                "flow": {
                   "flowId": 80032,
                   "subFlows": [
                    { 
                      "subFlowId": 76422
                    }, 
                    {
                       "subFlowId": 12654
                    }
                  ]
                    }
                   },
                   {
                      "subFlowId": 12422
                   }
               ]
            }

Unfortunately, my attempt to populate this returns an empty flowgroup. Here is my attempt: Here is mainflow :

   const mainFlow:Flow = { 
     flowId: 90112,
     subFlows: _subFlows
     }



   
   function processFlow(flow: Flow) {
     if (flow && flow.subFlows === undefined) {
        flowGroup.flows.set(flow.flowId, flow);
     } else if (flow && Array.isArray(flow.subFlows)) {
        for (const subFlow of flow.subFlows) {
            flowGroup.subFlows.set(subFlow.subFlowId, subFlow);
            if (subFlow.flow) {
                processFlow(subFlow.flow);
            }
        }
    }
}

processFlow(mainFlow);
console.log(`FlowGroup is ${JSON.stringify(flowGroup)}`);

Here is the data In used to create the test:

const subFlow1:SubFlow ={
 subFlowId: 52820
 }

const subFlow2:SubFlow ={
 subFlowId: 12422
}

 const flow3:SubFlow = {
  subFlowId: 76422
 }

 const flow4: SubFlow = {
  subFlowId: 12654
 }

 const flow5: Flow = {
  flowId: 80032,
   subFlows: [flow3, flow4]
 }

subFlow1.flow = flow5;  

 const flowGroup: FlowGroup = {
      flows: new Map<number, Flow>(),
      subFlows: new Map<number, Flow>()
    }



 const _subFlows = [subFlow1, subFlow2];

 const mainFlow:Flow ={
  flowId: 90112,
  subFlows: _subFlows
 }

Here is where I print the values of a map set manually: this prints the values on the console

    const m = new Map<string, Flow>();
    m.set(flow5.flowId, flow5);
    
    for(const [k, v] of m.entries()){
      console.log(` Map key = ${k} and value = 
             ${JSON.stringify(v)}`);
      }

These compiler settings for typescript are able to handle maps: You are assuming i am using es6.

   "target": "esNext",
   "module": "es2022",
   "moduleResolution": "node",

Please see some code I am using successfully in this app:

productHandler<Product, ProductKey
    extends keyof Product>(product: Product, productKey: ProductKey) {
    const map = new Map<ProductKey, Array<string>>();
    const productData = product[productKey] as unknown as Array<string>;
    map.set(productKey, productData)
    return map;
}

CodePudding user response:

I think I see what you're attempting to do. It would be clearer if you described inputs and outputs with an example.

The simplest way to handle recursive processing of a structure with N node types is with a set of N mutually recursive functions. Something like this:

type Flow = {
  flowId: number,
  subFlows?: Array<SubFlow>
} 

type SubFlow = {
  subFlowId: number,
  flow?: Flow,
}

type FlowGroup = {
  flows: Map<number,Flow>,
  subFlows: Map<number,Flow>
}
    
const subFlow1:SubFlow = {
  subFlowId: 52820
}

const subFlow2:SubFlow = {
  subFlowId: 12422
}

const flow3:SubFlow = {
  subFlowId: 76422
}

const flow4: SubFlow = {
  subFlowId: 12654
}

const flow5: Flow = {
  flowId: 80032,
  subFlows: [flow3, flow4]
}

subFlow1.flow = flow5;  

const _subFlows = [subFlow1, subFlow2];

const mainFlow: Flow = {
  flowId: 90112,
  subFlows: _subFlows
}

const flowGroup: FlowGroup = {
  flows: new Map<number, Flow>(),
  subFlows: new Map<number, Flow>()
}

function accumulateFlow(flow: Flow) {
  if (flow == null) {
    return;
  }
  flowGroup.flows.set(flow.flowId, flow);
  for (let subFlow of flow.subFlows) {
    accumulateSubflow(subFlow);
  }
}

function accumulateSubflow(subFlow: SubFlow) {
  flowGroup.subFlows.set(subFlow.subFlowId, subFlow);
  accumulateFlow(subFlow.flow);
}

accumulateFlow(mainFlow)
console.log('Flows '   JSON.stringify(Array.from(flowGroup.flows.keys())))
console.log('SubFlows '   JSON.stringify(Array.from(flowGroup.subFlows.keys())))

This produces

"Flows [90112,80032]"
"SubFlows [52820,76422,12654,12422]"

Either this is correct or I still misunderstand the problem.

In this case, accumulateSubflow is simple and only called once. So you could choose to inline it.

function accumulateFlow(flow: Flow) {
  if (flow == null) {
    return;
  }
  flowGroup.flows.set(flow.flowId, flow)
  for (let subFlow of flow.subFlows) {
    flowGroup.subFlows.set(subFlow.subFlowId, subFlow)
    accumulateFlow(subFlow.flow)
  }
}

The downside here is that if you ever have a structure where the root is a sub-flow rather than a flow, you're out of luck. With two functions, covering more cases in the future requires less thinking.

  • Related