1

Below is a recursive method to delete a comment from a deeply nested array. The code works, but here are my question:

QUESTION:

  1. I'm using _.remove within the loop to find and remove a comment in the current array. It seems expensive for obvious reasons i.e. loop within a loop, but other approaches seems just as expensive. I'm sure there are better ways to do this.

WORKING EXAMPLE:

https://plnkr.co/edit/PeW5ZFLynO2q8VNqbAHx?p=preview

    var comments = [
        {
            id: 1,
            depth: 0,
            subject: 'Subject one'
        },
        {
            id: 2,
            depth: 0,
            subject: 'Subject two',
            children: [
                {
                    id: 3,
                    depth: 1,
                    subject: 'Subject two dot one'
                },
                {
                    id: 4,
                    depth: 1,
                    subject: 'Subject two dot two'
                }
            ]
        },
        {
            id: 5,
            depth: 0,
            subject: 'Subject three',
            children: [
                {
                    id: 6,
                    depth: 1,
                    subject: 'Subject three dot one'
                },
                {
                    id: 7,
                    depth: 1,
                    subject: 'Subject three dot two',
                    children: [
                        {
                            id: 8,
                            depth: 2,
                            subject: 'Subject three dot two dot one'
                        },
                        {
                            id: 9,
                            depth: 2,
                            subject: 'Subject three dot two dot two'
                        }
                    ]
                }
            ]
        }
    ];

    function deleteComment(comment, comments) {
        var self = this,
            db = [];

        function removeComment(items, parent) {
            _.forEach(items, function (item) {

                // QUESTION - seems expensive as we have a loop in a loop
                _.remove(items, function(item) {
                    if (item.id === comment.id) {
                      console.log(item);
                      return true;
                    }
                    // NOTE: use above for demo purposes
                    // return item.id === comment.id
                });

                _.has(item, 'children')  ? removeComment(item.children, item) : 0;
            });
        }

      removeComment(comments, db);

    }

    var commentToBeDeleted = {           
        id: 8,
        depth: 2,
        subject: 'Subject three dot two dot one'
      };

    deleteComment(commentToBeDeleted, comments);
0

2 Answers 2

1

You could probably find a way to do this more efficiently with a .reduce() function to combine .forEach and _.remove. However, if the code works, it works!

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

1 Comment

thanks kyle, I'll take a look, now that you mention it I'll also see if I can do something with _.dropwhile. Side note, the problem is I'm finding as the application grows more of these expensive / poorly written pieces of code start to stack up and I end up with angular digest nightmares as well as overall performance issues.
1

I am not sure if this is the most performant way to accomplish this, but this is the most succinct way I have found:

It turns out JSON.stringify provides a callback for each visited JSON value being converted, which you can use to determine if the value should be included in the string. You can use this to visit each value without having to do the traversing yourself.

From MDN

The replacer parameter can be either a function or an array. As a function, it takes two parameters, the key and the value being stringified. The object in which the key was found is provided as the replacer's this parameter. Initially it gets called with an empty key representing the object being stringified, and it then gets called for each property on the object or array being stringified. It should return the value that should be added to the JSON string,

In your case the function would look something like

function deleteComment(commentToBeDeleted, comments) {
    return JSON.parse(JSON.stringify(comments, function(key, value) {
        if (commentToBeDeleted.id !== value.id) {
            return value;
        } 
    }));
}

Note: you probably don't want to use this code as is, as it leaves an empty node, but, you can insert what ever you logic you like into the callback, and this should get you started.

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.