JS:初始化&在一行代码中推送到多维数组?创建树结构

时间:2016-03-03 04:03:42

标签: javascript lodash

感谢Dave的主要解决方案,下面的答案是解决方案。旁注:如下所示,Dave提供的额外见解或作业对于新手非常有价值。帮助我们伸展。

此代码将遍历现有的JSON树,例如,您想要解析每个值,无论出于何种原因。它不是建造而是走路。在我的情况下,我正在走路并将每个评论解析为更丰富的课程:

var db = [], instance = {}, commentCounter = [];

function hydrateComments(items, parent) {
     _.forEach(items, function(item) {
        _.has(item, 'descendants') ? hydrateComments(item.descendants, item) : 0;

        instance = new CommentModel(_.omit(item,['descendants']));
         // other parsers go here, example the counter for each level
         // parseCounter(comment);

        (parent['children'] = (parent['children'] || [])) && item.depth > 0 ?
            parent.children.push(instance) :
            parent.push(instance);
    });
}

hydrateComments(comments, storeComments);

ANGULAR DIRECTIVE

对于那些使用此代码构建树的人,我包含一个可以帮助您使用上述树构建树的指令。

请注意我删除了很多我自己的代码并且没有对此进行测试,但我知道我花了很多时间试图找到树和模板,所以希望这对你有所帮助。

buildTree.$inject = [];
function buildTree() {
        link.$inject = ["scope", "elem", "attrs"];
        function link(scope, elem, attrs) {

        }

        CommentController.$inject = ["$scope"];
        function CommentController($scope) {

          $scope.$watchCollection(function () {
                return CommentDataService.getComments();
            },
            function (newComments, oldValue) {

                if (newComments) {
                    $scope.comments.model = newComments;
                }
            }, true);

        }

        return {
            restrict: "A",
            scope: {
               parent: "=cmoParent"
            },
            template: [
                "<div>",
                "<script type='text/ng-template'",
                    "id=" + '"' + "{[{ parent.app_id }]}" + '"' + " >",

                    "<div class='comment-post-column--content'>",
                        "<div cmo-comment-post",
                            "post-article=parent",
                            "post-comment=comment>",
                        "</div>",
                    "</div>",

                    "<ul ng-if='comment.children'>",
                        "<li class='comment-post-column--content'",
                            "ng-include=",
                            "'" + '"' + "{[{ parent.app_id }]}" + '"' + "'",
                            "ng-repeat='comment in comment.children",
                            "track by comment.app_id'>",
                        "</li>",
                    "</ul>",
                "</script>",


                "<ul class='conversation__timeline'>",
                    "<li class='conversation__post-container'",
                        "ng-include=",
                        "'" + '"' + "{[{ parent.app_id }]}" + '"' + "'",
                        "ng-repeat='comment in comments.model[parent.app_id]",
                        "track by comment.app_id'>",
                    "</li>",                
                    "<ul>",
                "</div>"

            ].join(' '),
            controller: CommentController,
            link: link
        }
    }

奖金

我也发现了一个很棒的技巧。如何使用一行代码初始化和填充数组。在我的情况下,我有一个计数器方法,将计算我使用提示的每个级别的每个评论:

parseCounter: function(comment) {
    var depth = comment.depth;
    (commentCounter[depth] = (commentCounter[depth] || [])) ? commentCounter[depth]++ : 0;
},

原始问题

下面的代码解析多级对象数组,目的是将所有对象解析为“CommentModel”的实例,虽然在这个例子中简单的是更丰富的对象类,但为了简洁起见,我简化了对象/类。

现有堆叠交换内容:

关于设置多维数组的内容很多,几乎所有内容都显示了例如:

var item[‘level1’][‘level2’] = ‘value’;  

var item = [];
var item['level1'] = [];

var item = new Array([]) // and or objects

但是,没有这样的例子:

var item[‘level1’].push(object)

问题:

  1. 有没有办法初始化2级深度多维数组,同时在一行代码中推送它?

    1.1即在parent[‘children’]下面的例子中,我被迫检查它是否存在,如果没有设置它。如果我尝试parent[‘children’].push(instance),我显然会推动未定义的异常。是否有单行或更好的方法来检查财产是否存在,如果不存在?我显然不能在每次迭代时在父级上设置一个空数组,即parent ['children'] = [];和父母['children'] =价值不会工作

  2. 是否可以将初始化和验证移动到 CommentModel实例?我问我试图 CommentModel.prototype['children'] = [];但后来所有的孩子('后代') 对象被添加到名为的proto属性中的每个对象 “孩子们”,这很有意义。

  3. 方面的问题 - 我认为我的树迭代代码function hydrateComments(items, parent)很简洁但是我能做些什么来进一步简化lodash和/或angular?我见过的大多数例子都是冗长的,并没有真正走过树枝。

  4. PLUNKER&amp;代码

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

        var comments = [
            {
                id: 1,
                depth: 0,
                subject: 'Subject one'
            },
            {
                id: 2,
                depth: 0,
                subject: 'Subject two',
                descendants: [
                    {
                        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',
                descendants: [
                    {
                        id: 6,
                        depth: 1,
                        subject: 'Subject three dot one'
                    },
                    {
                        id: 7,
                        depth: 1,
                        subject: 'Subject three dot two',
                        descendants: [
                            {
                                id: 8,
                                depth: 2,
                                subject: 'Subject three dot two dot one'
                            },
                            {
                                id: 9,
                                depth: 2,
                                subject: 'Subject three dot two dot two'
                            }
                        ]
                    }
                ]
            }
        ];
    
        function hydrateComments(items, parent) {
            _.forEach(items, function (item) {
                // create instance of CommentModel form comment. Simply example
                var instance = new CommentModel(item);
    
                // if we have descendants then injec the descendants array along with the
                // current comment object as we will use the instance as the "relative parent"
                if (_.has(instance, 'descendants')) {
                    hydrateComments(instance.descendants, instance);
                }
    
                // we check is parent has a property of children, if not, we set it
                // NOTE : 3 lines of code ? is there a more concise approach
                if (!_.has(parent, 'children')) {
                    parent['children'] = [];
                }
    
                // if depth id greater than 0, we push all instances of CommentModel of that depth to the
                // parent object property 'children'. If depth is 0, we push to root of array
                if (item.depth > 0) {
                    parent.children.push(instance);
                } else {
                    parent.push(instance);
                }
            })
        }
    
        // simple example, but lets assume much richer class / object
        function CommentModel(comment) {
            this.id = comment.id;
            this.depth = comment.depth;
            this.subject = comment.subject;
            this.descendants = comment.descendants;
        }
    
        var output = [];
        // init - pass in data and the root array i.e. output
        hydrateComments(comments, output);
    
        // Tada - a hydrated multi-level array
        console.log('Iteration output for comments  : ', output)
    

1 个答案:

答案 0 :(得分:1)

要在单个语句中初始化数组,您可以执行以下操作

  

方法1 :(初始化parent['children'])ANS到Q#1

排行榜#1:https://plnkr.co/edit/lmkq8mUWaVrclUY2CoMt?p=preview

function hydrateComments(items, parent) {
  _.forEach(items, function(item) {
    // create instance of CommentModel form comment. Simply example 
    var instance = new CommentModel(item);

    // if we have descendants then injec the descendants array along with the 
    // current comment object as we will use the instance as the "relative parent"
    _.has(instance, 'descendants') ? hydrateComments(instance.descendants, instance) : 0;

    //Less eff. and less readable then method #2
    (parent['children'] = (parent['children'] || [])) && item.depth > 0 ?
      parent.children.push(instance) :
      parent.push(instance);


  });
}
  

方法2 :(初始化parent['children'])ANS到Q#2 - 我更喜欢这个。

#2的引人注目:https://plnkr.co/edit/zBsF5o9JMb6ETHKOv8eE?p=preview

function CommentModel(comment) {
  this.id = comment.id;
  this.depth = comment.depth;
  this.subject = comment.subject;
  this.descendants = comment.descendants;
  //Initialise children in constructer itself! :)
  this.children = [];
}

function hydrateComments(items, parent) {
  _.forEach(items, function(item) {
    // create instance of CommentModel form comment. Simply example 
    var instance = new CommentModel(item);

    // if we have descendants then injec the descendants array along with the 
    // current comment object as we will use the instance as the "relative parent"
    _.has(instance, 'descendants') ? hydrateComments(instance.descendants, instance) : 0;

    item.depth > 0 ? parent.children.push(instance) : parent.push(instance);

  });
}
  

ANS到Q#3

我觉得你的代码还可以。但如果深度增加太多,您可能会遇到stackoverflow。使用trampolines通过递归解决此问题。但如果你确定深度不是

我想在上面的文章中引用几行:

  

此图表未显示的是30,000递归之后   调用浏览器挂起;到了它必须被强行关闭的程度   下。与此同时,蹦床继续蹦蹦跳跳数百人   成千上万的调用。这个数字没有实际限制   蹦床可以弹跳。

但是只使用trampoline,你知道深度足以导致堆栈溢出。

希望这有帮助!