0

I am currently trying to access an object and its properties but I can't seem to find a way to get objects that are not the first items in their respective children array. It can find numbers only if they're first in the array, but I think that I did the wrong thing in my function, and I am not quite sure how to fix it. What could be my mistakes and how do I fix this?

Here is the tree:

{
    name: "One",
    ids: {
        id: 1,
        level: 0
    },
    children: [
        {
            name: "Two",
            ids: {
                id: 2,
                level: 1
            },
            children: [
                {
                    name: "Three",
                    ids: {
                        id: 3,
                        level: 2
                    },
                    children: [
                        {
                            name: "Five",
                            ids: {
                                id: 5,
                                level: 3
                            },
                            children: [
                                {
                                    name: "Eight",
                                    ids: {
                                        id: 8,
                                        level: 4
                                    },
                                    children: []
                                },
                                {
                                    name: "Nine",
                                    ids: {
                                        id: 9,
                                        level: 4
                                    },
                                    children: []
                                },
                                {
                                    name: "Ten",
                                    ids: {
                                        id: 10,
                                        level: 4
                                    },
                                    children: []
                                }
                            ]
                        }
                    ]
                },
                {
                    name: "Four",
                    ids: {
                        id: 4,
                        level: 2
                    },
                    children: [
                        {
                            name: "Six",
                            ids: {
                                id: 6,
                                level: 3
                            },
                            children: []
                        },
                        {
                            name: "Seven",
                            ids: {
                                id: 7,
                                level: 3
                            },
                            children: []
                        }
                    ]
                }
            ]
        }
    ]
}

And here is my function:

findObj(obj, id) {
    if(obj.ids.id == id) {
        return obj;
    }
    else if(obj.children.length != 0) {
        for(var i in obj.children) {
            var temp = findObj(obj.children[i], id);
            if(temp != undefined) {
                return temp;
            }
        }
    }
}

3 Answers 3

2

How about using Recursive function like this

function findObj(obj, id) {
    let answer
    if(obj.ids.id == id) return obj
    findChildren(obj.children, id)

    function findChildren(children, id) {
        for(let i=0;i<children.length;i++) {
             if(children[i].ids.id === id) return answer = children[i]
             findChildren(children[i].children, id)
        } 
    }
    return answer
}
Sign up to request clarification or add additional context in comments.

1 Comment

The code didn't work but I think this gave me ideas on my other functions. Thank you.
1

You can do this using recursive approach with a single forEach loop.

const data = {"name":"One","ids":{"id":1,"level":0},"children":[{"name":"Two","ids":{"id":2,"level":1},"children":[{"name":"Three","ids":{"id":3,"level":2},"children":[{"name":"Five","ids":{"id":5,"level":3},"children":[{"name":"Eight","ids":{"id":8,"level":4},"children":[]},{"name":"Nine","ids":{"id":9,"level":4},"children":[]},{"name":"Ten","ids":{"id":10,"level":4},"children":[]}]}]},{"name":"Four","ids":{"id":4,"level":2},"children":[{"name":"Six","ids":{"id":6,"level":3},"children":[]},{"name":"Seven","ids":{"id":7,"level":3},"children":[]}]}]}]}

function findObj(obj, id) {
  let result = null;

  if (obj.ids.id === id) result = obj;
  if (obj.children) {
    obj.children.forEach(c => {
      if (!result) result = findObj(c, id)
    })
  }

  return result;
}

console.log(findObj(data, 6))
console.log(findObj(data, 5))
console.log(findObj(data, 1))

1 Comment

The code works, although I did a few changes to it. Thank you very much.
1

I like to separate out the object traversal from the code that is trying to find something. I would further separate out a generic deepFind function using a predicate from the details of your objects.

function * traverse (obj) {
  yield obj;
  for (let child of obj.children) {yield * traverse (child)}
}

const deepFind = (pred) => (obj) => {
  for (let node of traverse (obj)) {
    if (pred (node)) {return node} 
  }
}

const findById = (targetId) =>
  deepFind (({ids: {id}}) => id == targetId)

const objs = {name: "One", ids: {id: 1, level: 0}, children: [{name: "Two", ids: {id: 2, level: 1}, children: [{name: "Three", ids: {id: 3, level: 2}, children: [{name: "Five", ids: {id: 5, level: 3}, children: [{name: "Eight", ids: {id: 8, level: 4}, children: []}, {name: "Nine", ids: {id: 9, level: 4}, children: []}, {name: "Ten", ids: {id: 10, level: 4}, children: []}]}]}, {name: "Four", ids: {id: 4, level: 2}, children: [{name: "Six", ids: {id: 6, level: 3}, children: []}, {name: "Seven", ids: {id: 7, level: 3}, children: []}]}]}]}

console .log (findById (5) (objs))
.as-console-wrapper {max-height: 100% !important; top: 0}

Here traverse does a preorder traversal of your object (root first, then branches). It should work on any object with children array properties. (If these can be optional, it would be trivial to fix this up.) We write deepFind on top of that, taking a predicate and returning the first node that matches it, or undefined if none does.

Then findById is almost trivial. We just call deepFind with a predicate that checks your id condition.

I like this style of calling it like findById (5) (objs). I find it clarifies many things. But if you prefer to call findById(objs, 5), then we can use this instead:

const findById = (obj, targetId) =>
  deepFind (({ids: {id}}) => id == targetId) (obj)

Whenever you need a process that you want to stop on first match, generator functions become very useful.

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.