admin管理员组

文章数量:1416651

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?

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?

Share Improve this question edited Dec 10, 2021 at 6:42 PeterKA 24.7k5 gold badges27 silver badges52 bronze badges asked Dec 10, 2021 at 5:52 Web3guyWeb3guy 231 silver badge3 bronze badges 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. – www.admiraalit.nl Commented Dec 10, 2021 at 7:22
Add a ment  | 

5 Answers 5

Reset to default 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);

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 );

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)

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));

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, []);

本文标签: javascriptLooping through nested array of objectsStack Overflow