Skip to content

Instantly share code, notes, and snippets.

@gyenabubakar
Last active March 1, 2021 14:25
Show Gist options
  • Save gyenabubakar/f94c86d3ddb785cd801ce3bb3be22fa6 to your computer and use it in GitHub Desktop.
Save gyenabubakar/f94c86d3ddb785cd801ce3bb3be22fa6 to your computer and use it in GitHub Desktop.
Given an object 'fakeObj'; loop though all the properties of 'fakeObj' object and add them into an array. If there's a nested object, it should be removed from its parent object and added to the array directly. So, basically, all objects should be detached and made stand-alone in the final array, regardless of their position in the given object …
// example object
const fakeObj = {
key1: {
prop1: true,
prop2: 34,
prop3: 'Hello',
prop4: [],
},
key2: {
prop1: true,
prop2: {
subprop1: [],
subprop2: 234,
subprop3: {
a: [],
b: false,
},
},
prop3: 'Hello',
prop4: [],
},
key3: {
prop1: true,
prop2: 34,
prop3: 'Hello',
prop4: [],
},
};
// function to return the final array of standalone objects
function mergeObjectsToArray(object) {
// array of standalone objects
const arr = [];
// go through the passed object
// check if properties are objects
// detach them and add them directly in the target array, 'arr'
validateAndAddObj(object, arr);
// return array of standalone objects
return arr;
}
function validateAndAddObj(object, targetArray) {
// for every first-level property
for (const prop in object) {
// object to keep track of element
const element = {};
// check if property is indeed a property of object
if (Object.hasOwnProperty.call(object, prop)) {
for (const subProp in object[prop]) {
// check if the property is a reference to an object; not an array
if ( !(typeof object[prop][subProp] === 'object' && !Array.isArray(object[prop][subProp]) ) ) {
// if yes, run though the object again
validateAndAddObj(object[prop][subProp]);
} else {
// if it's not an object, add it as a property to tracking object, 'element'
element[subProp] = object[prop][subProp];
targetArray.push(element);
break;
}
}
}
}
}
module.exports.mergeObjectsToArray = mergeObjectsToArray;
module.exports.validateAndAddObj = validateAndAddObj;
@jherr
Copy link

jherr commented Feb 12, 2021

const fakeObj = {
  key1: {
    prop1: true,
    prop2: 34,
    prop3: "Hello",
    prop4: [],
  },
  key2: {
    prop1: true,
    prop2: {
      subprop1: [],
      subprop2: 234,
      subprop3: {
        a: [],
        b: false,
      },
    },
    prop3: "Hello",
    prop4: [],
  },
  key3: {
    prop1: true,
    prop2: 34,
    prop3: "Hello",
    prop4: [],
  },
};

// function to return the final array of standalone objects
function mergeObjectsToArray(object) {
  // array of standalone objects
  const arr = [];

  // go through the passed object
  // check if properties are objects
  // detach them and add them directly in the target array, 'arr'
  validateAndAddObj(object, arr);

  // return array of standalone objects
  return arr;
}

function validateAndAddObj(object, targetArray) {
  if (typeof object === "object") {
    const element = {};
    for (const prop in object) {
      if (typeof object[prop] === "object") {
        validateAndAddObj(object[prop], targetArray);
      } else {
        element[prop] = object[prop];
      }
    }
    if (Object.keys(element).length) {
      targetArray.push(element);
    }
  }
}

module.exports.mergeObjectsToArray = mergeObjectsToArray;
module.exports.validateAndAddObj = validateAndAddObj;

console.log(mergeObjectsToArray(fakeObj));

@gyenabubakar
Copy link
Author

@jherr This yields a result that's very close to the expect result.

In this result:

[
   { prop1: true, prop2: 34, prop3: 'Hello' },
   { b: false },
   { subprop2: 234 },
   { prop1: true, prop3: 'Hello' },
   { prop1: true, prop2: 34, prop3: 'Hello' }
]

You'll see that all the arrays have been omitted. For instace, the property prop4 in key1, which is an array, doesn't appear in the flattened object (array).

They're supposed to be included.

@jherr
Copy link

jherr commented Feb 12, 2021

Ah, ok:

function validateAndAddObj(object, targetArray) {
  if (typeof object === "object") {
    const element = {};
    for (const prop in object) {
      if (
        typeof object[prop] === "object" &&
        Array.isArray(object[prop]) === false
      ) {
        validateAndAddObj(object[prop], targetArray);
      } else {
        element[prop] = object[prop];
      }
    }
    if (Object.keys(element).length) {
      targetArray.push(element);
    }
  }
}

Or perhaps more preferable:

// example object
const fakeObj = {
  key1: {
    prop1: true,
    prop2: 34,
    prop3: "Hello",
    prop4: [],
  },
  key2: {
    prop1: true,
    prop2: {
      subprop1: [],
      subprop2: 234,
      subprop3: {
        a: [],
        b: false,
      },
    },
    prop3: "Hello",
    prop4: [],
  },
  key3: {
    prop1: true,
    prop2: 34,
    prop3: "Hello",
    prop4: [],
  },
};

// function to return the final array of standalone objects
export function mergeObjectsToArray(
  object: Record<string, unknown>
): Record<string, unknown>[] {
  // array of standalone objects
  const arr = [];

  // go through the passed object
  // check if properties are objects
  // detach them and add them directly in the target array, 'arr'
  validateAndAddObj(object, arr);

  // return array of standalone objects
  return arr;
}

export function validateAndAddObj(
  object: Record<string, unknown>,
  targetArray: Record<string, unknown>[]
): void {
  if (typeof object === "object") {
    const element = {};
    for (const prop in object) {
      if (
        typeof object[prop] === "object" &&
        Array.isArray(object[prop]) === false
      ) {
        validateAndAddObj(object[prop] as Record<string, unknown>, targetArray);
      } else {
        element[prop] = object[prop];
      }
    }
    if (Object.keys(element).length) {
      targetArray.push(element);
    }
  }
}

console.log(mergeObjectsToArray(fakeObj));

@gyenabubakar
Copy link
Author

@jherr you're the man! problem solved!! Thank you sir!

@jherr
Copy link

jherr commented Feb 12, 2021

So, at the end of the day. Two big takeaways from me on this:

  1. Recursion was probably unavoidable here. Sadly. You use a stack to avoid the recursion. But recursion is using a stack anyway, so your just trading your own version of a stack for the language's stack, which is needless complexity.
  2. I think the real issue was around the subProp stuff. Generally with recursion you want to do with the current level of recursion and not drill-down. You leave the drilling down to the next level of recursion.

Hope that helps ... a little.

@gyenabubakar
Copy link
Author

Oh okay. It helps, a lot. I'm grateful.

@Jahkamso
Copy link

Jahkamso commented Mar 1, 2021

I'm very gratefulful..
Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment