【问题标题】:Iterate specific nested object property and push to array迭代特定的嵌套对象属性并推送到数组
【发布时间】:2019-08-05 11:29:32
【问题描述】:

如果我需要遍历每个对象属性以找到 nextStep 并推送到数组,那么下面显示的对象。我的输出应该有一个包含所有“nextStep”属性的数组变量。

输入:

{
  "Product1": {
    "stepName": "step1",
    "stepOutputStatus": "normal",
    "nextStep": {
      "stepName": "step2",
      "stepOutputStatus": "normal",
      "nextStep": {
        "stepName": "step3",
        "stepOutputStatus": "warning",
        "nextStep": {
          "stepName": "step4",
          "stepOutputStatus": "warning",
          "nextStep": null
        }
      }
    }
  }
}

预期输出:

[
  {
    "stepName": "step2",
    "stepOutputStatus": "normal"
  },
  {
    "stepName": "step3",
    "stepOutputStatus": "warning"
  },
  {
    "stepName": "step4",
    "stepOutputStatus": "warning"
  }
]

我尝试了以下代码,但由于范围问题,它返回 null:

function iterObj(obj) {
  var result = [];
  for (var key in obj) {
    if (
      obj[key] !== null &&
      typeof obj[key] === "object" &&
      key == "nextStep"
    ) {
      var data = this.iterObj(obj[key]);
      result.push(data);
    }
  }
  return result;
}

iterObj(obj);

【问题讨论】:

    标签: javascript arrays javascript-objects


    【解决方案1】:

    您可以使用 JavaScript 生成器进行迭代(不使用递归)。
    直接下到下一步,直到没有定义。

    如果你对function *不熟悉,请参考MDN文档。

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*

    const product = {
      stepName: "step1",
      stepOutputStatus: "normal",
      nextStep: {
        stepName: "step2",
        stepOutputStatus: "normal",
        nextStep: {
          stepName: "step3",
          stepOutputStatus: "warning",
          nextStep: {
            stepName: "step4",
            stepOutputStatus: "warning",
            nextStep: null
          }
        }
      }
    };
    
    function* iterObj(obj) {
      while (obj.nextStep) {
        const { stepName, stepOutputStatus } = obj;
        yield { stepName, stepOutputStatus };
        obj = obj.nextStep;
      }
    }
    
    const iterator = iterObj(product);
    console.log(Array.from(iterator));

    【讨论】:

    • 作为替代方案,也可以将obj 推送到循环中的数组并在最后返回...但是生成器也很适合这里...
    • 我正在使用递归,但突然之间它看起来很难阅读。生成器的想法突然出现在我的 ? 中 ?
    • 好吧,在这种情况下,一个简单的while 循环就足够了,这就是我赞成的主要原因......在这种情况下,生成器只是语法糖......
    • 谢谢@JonasWilms。我还发现 kemikofa 的 answer 是一种优雅的递归方式。
    • @SungM.Kim 我承认迭代器非常聪明。我从没想过将函数生成器与 Array.from 结合起来。
    【解决方案2】:

    递归函数,它将复制与给定密钥不匹配的每个密钥,用于更深入。

    const obj = {
      "Product1": {
        "stepName": "step1",
        "stepOutputStatus": "normal",
        "nextStep": {
          "stepName": "step2",
          "stepOutputStatus": "normal",
          "nextStep": {
            "stepName": "step3",
            "stepOutputStatus": "warning",
            "nextStep": {
              "stepName": "step4",
              "stepOutputStatus": "warning",
              "nextStep": null
            }
          }
        }
      }
    };
    
    function getDataBehindKey(key, ptr) {
      if (!ptr) {
        return [];
      }
    
      return Object.keys(ptr).reduce((tmp, x) => {
        if (x === key) {
          return [
            ...tmp,
            ...getDataBehindKey(key, ptr[x]),
          ];
        }
    
        tmp[0][x] = ptr[x];
    
        return tmp;
      }, [{}]);
    }
    
    console.log(getDataBehindKey('nextStep', obj.Product1));

    【讨论】:

      【解决方案3】:

      您可以使用扩展语法和解构递归地执行此操作。

      const data={"Product1":{"stepName":"step1","stepOutputStatus":"normal","nextStep":{"stepName":"step2","stepOutputStatus":"normal","nextStep":{"stepName":"step3","stepOutputStatus":"warning","nextStep":{"stepName":"step4","stepOutputStatus":"warning","nextStep":null}}}}}
      
      function handleData({nextStep, ...rest}){
        const res = [];
        res.push(rest);
        if(nextStep){
           res.push(...handleData(nextStep));
        }
        return res;
      }
      
      const res = handleData(data.Product1);
      
      console.log(res);

      更紧凑的版本:

      const data={"Product1":{"stepName":"step1","stepOutputStatus":"normal","nextStep":{"stepName":"step2","stepOutputStatus":"normal","nextStep":{"stepName":"step3","stepOutputStatus":"warning","nextStep":{"stepName":"step4","stepOutputStatus":"warning","nextStep":null}}}}}
      
      const handleData = ({nextStep, ...rest}) => [rest].concat(nextStep ? handleData(nextStep) : []);
      
      const res = handleData(data.Product1);
      
      console.log(res);

      【讨论】:

      • 这是非常优雅的递归。我希望我最初能写出这样的递归?
      • ...但它为每个递归调用创建和销毁一个数组...这不是性能方面的
      • 感谢 Sung M 和 Kemicofa 的解决方案
      【解决方案4】:

      let obj={
        "Product1": {
          "stepName": "step1",
          "stepOutputStatus": "normal",
          "nextStep": {
            "stepName": "step2",
            "stepOutputStatus": "normal",
            "nextStep": {
              "stepName": "step3",
              "stepOutputStatus": "warning",
              "nextStep": {
                "stepName": "step4",
                "stepOutputStatus": "warning",
                "nextStep": null
              }
            }
          }
        }
      }
      
      let output=[];
      
      
      function iterObj(obj) {
        while(obj.nextStep!=null && obj.hasOwnProperty('nextStep')){
          getNextStep(obj.nextStep);
          obj=obj.nextStep;
        }
      }
      
      function getNextStep(object){
        if(object.hasOwnProperty('nextStep')){
           var data = {stepName:object.stepName,stepOutputStatus:object.stepOutputStatus};
           output.push(data);
        }
      }
      
      iterObj(obj["Product1"]);
      console.log(output);

      【讨论】:

        猜你喜欢
        • 2020-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-06
        • 1970-01-01
        相关资源
        最近更新 更多