遍历嵌套的对象数组

Posted

技术标签:

【中文标题】遍历嵌套的对象数组【英文标题】:Looping through nested array of objects 【发布时间】:2022-01-14 21:30:56 【问题描述】:

我有以下对象数组,其中包含嵌套数组。我想遍历这些数组并将所有这些影响信息提取到单独的数组中:

这是我的输入数据的样子:


    "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"
                    ]
                
            ]
        
    ]

预期输出:

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

我目前正在尝试使用如下的 forEach 循环:

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

有没有更好更短的方法来做同样的事情?

【问题讨论】:

有更短的方法来做同样的事情,但以牺牲可读性为代价。我认为您的代码比下面的任何答案都好,因为很容易看到发生了什么,因此更容易维护,并且引入错误的风险很低。这比节省几行代码重要得多。 【参考方案1】:

您可以实现如下 sn-p 的结果:

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

【讨论】:

【参考方案2】:

应该这样做:

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

或者:对你的稍作修改

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

【讨论】:

值得考虑的好选择。您会向专业编写业务关键型软件的专业人士推荐哪种解决方案? 在这种情况下,任何一个选择都可以,尽管第二个选择可能会快一点。始终考虑易于理解的性能和代码,尤其是后期,因此更易于维护。 是的,我同意,因此,我会选择 OP 的原始解决方案。 此解决方案是否适用于无限级别的数据集?【参考方案3】:

这是你的解决方案

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)

可运行代码是

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)

【讨论】:

【参考方案4】:

我觉得递归将成为你的朋友,优点是无论你如何改变嵌套级别,它都会继续工作。

这将返回一个你正在寻找的数组:

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

【讨论】:

【参考方案5】:

您可以像这样创建一个 reducer 函数来对您的影响数据进行分组。

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

【讨论】:

以上是关于遍历嵌套的对象数组的主要内容,如果未能解决你的问题,请参考以下文章

遍历具有深层嵌套对象和数组的对象数组

如何遍历对象数组以便在 Mongodb 嵌套数组中推送数据

从嵌套属性数组中获取对象嵌套值

json数组存储了两个对象,要怎么遍历

Node.js 循环遍历嵌套的 Javascript 对象

js 对象属性遍历