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.