2

Have an object shown below were I need to iterate over each object property to find nextStep and push to an array. My output should have a single array variable with all "nextStep" properties.

Input:

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

Expected Output:

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

I tried below code, but it returns null due to scoping issue:

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

4 Answers 4

3

You can iterate using a JavaScript generator (without using recursion).
Just step down to the next step until it's not defined.

If you are unfamiliar with function *, please refer to MDN documentation.

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

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

6 Comments

As an alternative one could also just push obj to an array in the loop and return it at the end ... however the generator is also a good fit here ...
I was using a recursion but all of a sudden it looked hard to read. The generator idea just popped up in my 🧠 out of nowhere 😉
well, in this case a simple while loop is just enough, thats the primary reason I upvoted ... the generator is just syntactic sugar in this case...
Thanks @JonasWilms. I also found kemikofa's answer an elegant way to recurse over.
@SungM.Kim I admit that the iterator is very smart. I never thought to combine a function generator with Array.from.
|
2

You can do this recursively with spread syntax and destructuring.

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

More compact version:

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

3 Comments

This is very elegant recursion. I wish I could've written a recursion like this initially 👍
... but it creates and destroys an array for every recursive call ... which is not that performancewise
Thanks for the solutions to Sung M and Kemicofa
0

Recursive function that will copy every key that is not matching the given one which is used to go deeper.

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

Comments

0

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

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.