2

I have following array of objects with nested arrays in it. I wanted to traverse through those arrays and extract all those impact information to separate array:

this is how my input data looks like:

{
    "violations": [{
            "impact": "serious",
            "nodes": [{
                "any": [{
                        "impact": "critical"
                    },
                    {
                        "impact": "serious"
                    }
                ],
                "all": [{
                    "impact": "moderate"
                }],
                "none": [{
                    "impact": "minor"
                }]
            }]
        },
        {
            "impact": "serious",
            "nodes": [{
                "any": [{
                        "impact": "serious"
                    },
                    {
                        "impact": "minor"
                    }
                ],
                "all": [{
                    "impact": "moderate"
                }],
                "none": [{
                    "impact": "serious"
                }]
            }]
        },
        {
            "impact": "serious",
            "nodes": [{
                    "any": [{
                            "impact": "critical"
                        },
                        {
                            "impact": "critical"
                        }
                    ],
                    "all": [{
                        "impact": "moderate"
                    }],
                    "none": [{
                        "impact": "moderate"
                    }]
                },
                {
                    "any": [{
                            "impact": "critical"
                        },
                        {
                            "impact": "critical"
                        }
                    ],
                    "all": [{
                        "impact": "moderate"
                    }],
                    "none": [{
                        "impact": "moderate"
                    }]
                }
            ]
        }
    ]
}

expected output:

[
  {
    "impact": "serious"
  },
  {
    "impact": "critical"
  },
  {
    "impact": "serious"
  },
  {
    "impact": "moderate"
  },
  {
    "impact": "minor"
  },
  {
    "impact": "serious"
  },
  {
    "impact": "serious"
  },
  {
    "impact": "minor"
  },
  ......
]

I'm currently trying with forEach loop like below:

const results = [];
violations.forEach(({ nodes, impact }) => {
  results.push({ impact });
  // flattening nodes
  nodes.forEach(({ any, all, none }) => {
    any.forEach((v) => results.push(v));
    all.forEach((v) => results.push(v));
    none.forEach((v) => results.push(v));
  });
});

is there any better and shorter way to do the same?

1
  • There are shorter ways to do the same, but at the expense of readability. I think your code is better than any of the answers below, because it is easy to see what happens and therefore easier to maintain with low risk of introducing bugs. That is much more important than saving a few lines of code. Commented Dec 10, 2021 at 7:22

5 Answers 5

2

You can achieve your result like below snippet:

const items = {
  "violations": [
    {
      "impact": "serious",
      "nodes": [
        {
          "any": [
            {
              "impact": "critical"
            },
            {
              "impact": "serious"
            }
          ],
          "all": [
            {
              "impact": "moderate"
            }
          ],
          "none": [
            {
              "impact": "minor"
            }
          ]
        }
      ]
    },
    {
      "impact": "serious",
      "nodes": [
        {
          "any": [
            {
              "impact": "serious"
            },
            {
              "impact": "minor"
            }
          ],
          "all": [
            {
              "impact": "moderate"
            }
          ],
          "none": [
            {
              "impact": "serious"
            }
          ]
        }
      ]
    },
    {
      "impact": "serious",
      "nodes": [
        {
          "any": [
            {
              "impact": "critical"
            },
            {
              "impact": "critical"
            }
          ],
          "all": [
            {
              "impact": "moderate"
            }
          ],
          "none": [
            {
              "impact": "moderate"
            }
          ]
        },
        {
          "any": [
            {
              "impact": "critical"
            },
            {
              "impact": "critical"
            }
          ],
          "all": [
            {
              "impact": "moderate"
            }
          ],
          "none": [
            {
              "impact": "moderate"
            }
          ]
        }
      ]
    }
  ]
}

const newItems = items.violations.reduce((acc, {impact, nodes})=> {
  acc.push({impact});
  nodes.forEach(item => {
    Object.keys(item).forEach(key => {
      acc.push(...item[key]);
    })
  })
  return acc
}, []);

console.log(newItems);

Sign up to request clarification or add additional context in comments.

Comments

1

This should do it:

const impacts = data.violations.map(({impact,nodes}) => 
    [{impact}, ...nodes.map(({any,all,none}) => [...any, ...all, ...none]).flat()]
)
.flat();

const data =    {
    "violations": [{
            "impact": "serious",
            "nodes": [{
                "any": [{
                        "impact": "critical"
                    },
                    {
                        "impact": "serious"
                    }
                ],
                "all": [{
                    "impact": "moderate"
                }],
                "none": [{
                    "impact": "minor"
                }]
            }]
        },
        {
            "impact": "serious",
            "nodes": [{
                "any": [{
                        "impact": "serious"
                    },
                    {
                        "impact": "minor"
                    }
                ],
                "all": [{
                    "impact": "moderate"
                }],
                "none": [{
                    "impact": "serious"
                }]
            }]
        },
        {
            "impact": "serious",
            "nodes": [{
                    "any": [{
                            "impact": "critical"
                        },
                        {
                            "impact": "critical"
                        }
                    ],
                    "all": [{
                        "impact": "moderate"
                    }],
                    "none": [{
                        "impact": "moderate"
                    }]
                },
                {
                    "any": [{
                            "impact": "critical"
                        },
                        {
                            "impact": "critical"
                        }
                    ],
                    "all": [{
                        "impact": "moderate"
                    }],
                    "none": [{
                        "impact": "moderate"
                    }]
                }
            ]
        }
    ]
};
    
const impacts = data.violations.map(({impact,nodes}) => 
    [{impact}, ...nodes.map(({any,all,none}) => [...any, ...all, ...none]).flat()]
)
.flat();

console.log( impacts );

OR: A slight modification to yours

let results = [];
data.violations.forEach(({nodes,impact}) => {
    results.push({impact});
    // flattening nodes
    nodes.forEach(({any,all,none}) =>
        results.concat(...[...any, ...all, ...none])
    );
});

const data =    {
    "violations": [{
            "impact": "serious",
            "nodes": [{
                "any": [{
                        "impact": "critical"
                    },
                    {
                        "impact": "serious"
                    }
                ],
                "all": [{
                    "impact": "moderate"
                }],
                "none": [{
                    "impact": "minor"
                }]
            }]
        },
        {
            "impact": "serious",
            "nodes": [{
                "any": [{
                        "impact": "serious"
                    },
                    {
                        "impact": "minor"
                    }
                ],
                "all": [{
                    "impact": "moderate"
                }],
                "none": [{
                    "impact": "serious"
                }]
            }]
        },
        {
            "impact": "serious",
            "nodes": [{
                    "any": [{
                            "impact": "critical"
                        },
                        {
                            "impact": "critical"
                        }
                    ],
                    "all": [{
                        "impact": "moderate"
                    }],
                    "none": [{
                        "impact": "moderate"
                    }]
                },
                {
                    "any": [{
                            "impact": "critical"
                        },
                        {
                            "impact": "critical"
                        }
                    ],
                    "all": [{
                        "impact": "moderate"
                    }],
                    "none": [{
                        "impact": "moderate"
                    }]
                }
            ]
        }
    ]
};
    
let results = [];
data.violations.forEach(({ nodes, impact }) => {
  results.push({ impact });
  // flattening nodes
  nodes.forEach(({ any, all, none }) => 
      results = results.concat(...[...any, ...all, ...none])  
  );
});

console.log( results );

4 Comments

Good options to consider. Which solution would you recommend to a professional writing business-critical software?
In this case either choice is fine, even though the second choice may be a little bit faster. Always consider performance and code that's easy to understand, especially later, and therefore easier to maintain.
Yes, I agree and therefore, I would choose OP's original solution.
is this solution works for the infinite levels of data set?
1

here is your solution

let output = []
function recursion(obj, op) {
    if (typeof obj === 'object') {
        if (obj.impact) {
            op.push({ impact: obj.impact })
        }
        for (var key in obj) {
            recursion(obj[key], op)
        }
    }
    return
}

recursion(obj, output)
console.log(output)

Runnable code is

let obj = {
    "violations": [
        {
            "impact": "serious",
            "nodes": [
                {
                    "any": [
                        {
                            "impact": "critical"
                        },
                        {
                            "impact": "serious"
                        }
                    ],
                    "all": [
                        {
                            "impact": "moderate"
                        }
                    ],
                    "none": [
                        {
                            "impact": "minor"
                        }
                    ]
                }
            ]
        },
        {
            "impact": "serious",
            "nodes": [
                {
                    "any": [
                        {
                            "impact": "serious"
                        },
                        {
                            "impact": "minor"
                        }
                    ],
                    "all": [
                        {
                            "impact": "moderate"
                        }
                    ],
                    "none": [
                        {
                            "impact": "serious"
                        }
                    ]
                }
            ]
        },
        {
            "impact": "serious",
            "nodes": [
                {
                    "any": [
                        {
                            "impact": "critical"
                        },
                        {
                            "impact": "critical"
                        }
                    ],
                    "all": [
                        {
                            "impact": "moderate"
                        }
                    ],
                    "none": [
                        {
                            "impact": "moderate"
                        }
                    ]
                },
                {
                    "any": [
                        {
                            "impact": "critical"
                        },
                        {
                            "impact": "critical"
                        }
                    ],
                    "all": [
                        {
                            "impact": "moderate"
                        }
                    ],
                    "none": [
                        {
                            "impact": "moderate"
                        }
                    ]
                }
            ]
        }
    ]
}
let output = []
function recursion(obj, op) {
    if (typeof obj === 'object') {
        if (obj.impact) {
            op.push({ impact: obj.impact })
        }
        for (var key in obj) {
            recursion(obj[key], op)
        }
    }
    return
}

recursion(obj, output)
console.log(output)

Comments

0

I feel like recursion is going to be your friend on this one, the advantage being that it will continue to work no matter how much you change your levels of nesting.

This will return an array like what you are looking for:

function extractImpactInformation(data) {
  const results = [];
  if (typeof data === 'object') {
    if (data['impact']) {
      results.push({ 'impact': data['impact'] });
    }
    for (const key in data) {
      results.push(...extractImpactInformation(data[key]));
    }
  }
  
  return results;
}

const testData = {
  "violations": [
    {
      "impact": "serious",
      "nodes": [
        {
          "any": [
            {
              "impact": "critical"
            },
            {
              "impact": "serious"
            }
          ],
          "all": [
            {
              "impact": "moderate"
            }
          ],
          "none": [
            {
              "impact": "minor"
            }
          ]
        }
      ]
    },
    {
      "impact": "serious",
      "nodes": [
        {
          "any": [
            {
              "impact": "serious"
            },
            {
              "impact": "minor"
            }
          ],
          "all": [
            {
              "impact": "moderate"
            }
          ],
          "none": [
            {
              "impact": "serious"
            }
          ]
        }
      ]
    },
    {
      "impact": "serious",
      "nodes": [
        {
          "any": [
            {
              "impact": "critical"
            },
            {
              "impact": "critical"
            }
          ],
          "all": [
            {
              "impact": "moderate"
            }
          ],
          "none": [
            {
              "impact": "moderate"
            }
          ]
        },
        {
          "any": [
            {
              "impact": "critical"
            },
            {
              "impact": "critical"
            }
          ],
          "all": [
            {
              "impact": "moderate"
            }
          ],
          "none": [
            {
              "impact": "moderate"
            }
          ]
        }
      ]
    }
  ]
}

function extractImpactInformation(data) {
  const results = [];
  if (typeof data === 'object') {
    if (data['impact']) {
      results.push({ 'impact': data['impact'] });
    }
    for (const key in data) {
      results.push(...extractImpactInformation(data[key]));
    }
  }
  
  return results;
}

console.log(extractImpactInformation(testData));

Comments

0

you can create a reducer function like this to group your impact data.

const impactReducer = (acc, {impact, nodes}) => {
  if (impact) acc.push({impact});
  
  nodes?.forEach(node => Object.keys(node).forEach(key => node[key].reduce(impactReducer, acc)));  
  
  return acc;
};

const impacts = items.violations.reduce(impactReducer, []);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.