Coding/Blog challenge 14

Coding/Blog challenge 14

·

4 min read

This is a problem I received recently in a whiteboarding interview, during the interview I stumbled a bit & didn't quite come up with a definitive answer. But, I hadn't encountered a problem quite like this before, and I NEEDED to solve it. It was running around in my head all day at my day job, driving me nuts. So, I sat down and used the same method I began with in the interview, recursion and all.

Recursion can be a very tricky concept to wrap your head around. But the more you mess with it, the easier it becomes. In this situation, it came naturally, which makes me proud of myself. You have to pat yourself on your back for your wins in these types of endeavors. Those wins are what keep you going & give you the confidence to keep moving forward.

Real whiteboarding interview question

You are given a data table that looks like this:

image.png

create a function that takes in an Id number and outputs all related names as a URL path. Relative data will be based off of the parentId.

So, using the table above, if this function is passed the number 7(Taylor-made-9-iron), it would output:

products/golf-clubs/taylor-made-9-iron

The 9-iron has a parent which is named golf-clubs, who has a parent named products.

My thought process

First, I will define some data to use for testing. This is an array of objects:

//our mock data
const dataArrObj = [
    { id: 1, name: 'Home', parentId: null },
    { id: 2, name: 'Products', parentId: null },
    { id: 3, name: 'Consoles', parentId: 2 },
    { id: 4, name: 'Xbox-1', parentId: 3 },
    { id: 5, name: 'PS5', parentId: 3 },
    { id: 6, name: 'Golf-Clubs', parentId: 2 },
    { id: 7, name: 'Taylor-Made-9-iron', parentId: 6 },
]

Then, I create a container to hold my output, I do this outside of my function so that its value will not be reset when the function is used recursively. After that, I will define my function which will take in an ID number. I also know that I want to loop over the data, to do this I chose to use the for/in loop.

const dataArrObj = [
    { id: 1, name: "Home", parentId: null },
    { id: 2, name: "Products", parentId: null },
    { id: 3, name: "Consoles", parentId: 2 },
    { id: 4, name: "Xbox-1", parentId: 3 },
    { id: 5, name: "PS5", parentId: 3 },
    { id: 6, name: "Golf-Clubs", parentId: 2 },
    { id: 7, name: "Taylor-Made-9-iron", parentId: 6 },
];

// container for what will be returned
let container = [];

// our function with id parameter
function relativeURL(id) {
    // iterate over all objects in data array
    for (let aObj in dataArrObj) {
    }
    return container;
}

Then it makes sense to set a new variable for each object contained in the array. This variable will be reset to the current object as we iterate, it will make things easier to read. As we loop, IF the current object has an ID that is the same as the ID passed in as the argument & IF this object has a parent ID, then we want to store that object's name in our container array. Instead of Array push, which adds a new item to the end of an array, we will use the Array unshift. Unshift will add a new item at the beginning of an array.

function relativeURL(id) {
    for (let aObj in dataArrObj) {
        let thisObj = dataArrObj[aObj];
        //when current obj id same as function's argument
        if (thisObj.id == id) {
            //if current obj has a parentID
            if (thisObj.parentId) {
                //place obj name at beginning of container arr
                container.unshift(thisObj.name);

        }
    }
    return container;
}

Enter Recursion At this point, after the object's name is placed into the container array, we want to call the function over again. The difference now, is that we will pass in the parent ID as the function's argument. This will repeat until the current object does NOT have a parent ID. Then, we will unshift that last object's name, as it will be the root of our URL path. Last, we need to output what the container array, joined with forward slashes between each element.

function relativeURL(id) {
    for (let aObj in dataArrObj) {
        let thisObj = dataArrObj[aObj];

        if (thisObj.id == id) {
            if (thisObj.parentId) {
                container.unshift(thisObj.name);
                //start func. again with current obj parent ID
                relativeURL(thisObj.parentId);

            //when we've reach obj with no parent ID
            } else {
                //place this obj name at beginning of container
                container.unshift(thisObj.name);
            }
        }
    }
    //output the container joined with forward slash
    return container.join("/");
}

That is my solution to this particular challenge. I imagine there are other ways of doing this more efficiently & would love to know if you have a different solution!

Thanks for reading!