推送到数组并从递归函数返回它

时间:2016-09-13 10:26:36

标签: javascript arrays recursion

我想迭代一个结构,将所选节点推送到一个数组并返回所有结构。

var structure = {
    folder: getFolder(1, 'name1'),
    children: [
        {
            folder: getFolder(2, 'name2'),
            children: [
                {
                    folder: getFolder(4, 'name2'),
                    children: []
                }
            ]
        },
        {
            folder: getFolder(3, 'name3'),
            children: []
        }
    ]
};

例如,如果文件夹节点与getFolder(x,' name2')匹配,我会得到一个包含两个元素的数组:

folder: getFolder(2, 'name2'),
children: [
    {
        folder: getFolder(4, 'name2'),
        children: []
    }
]

folder: getFolder(4, 'name2'),
children: []

因为两者都符合给定的标准。我想出的功能是:

var searchAll = function (data, searchFor, results) {
    results = results || [];
    if (data[searchFor.type] != undefined &&
        data[searchFor.type][searchFor.index].indexOf(searchFor.value) !== -1) {
        return data;
    }
    if (data.children != null) {
        var result = null;
        for (var i = 0; result == null && i < data.children.length; i++) {
            results.push(searchAll(data.children[i], searchFor, results));
        }
    }
    return results;
};

searchAll(structure, {
    type: 'folder',
    index: 'name',
    value: 'name2'
});

但它返回undefined。我该怎么做?

2 个答案:

答案 0 :(得分:1)

使用递归构建数组的关键是concat()方法,它将在递归堆栈中一直正确地返回数组的副本。

在下面的示例中,使用push()添加符合条件的对象,而递归搜索子对象,并将其结果连接到结果数组。为简单起见,我使用了getFolder()函数在数据中返回的结果:

var structure = {
  folder: {id:1, name:'name1'}, //getFolder(1, 'name1'),
  children: [{
    folder: {id:2, name:'name2'}, //getFolder(2, 'name2'),
    children: [{
      folder: {id:4, name:'name2'}, //getFolder(4, 'name2'),
      children: []
    }]
  }, {
    folder: {id:3, name:'name3'}, //getFolder(3, 'name3'),
    children: []
  }]
};

function searchAll(object, criteria) {
  var i, j, result = [];

  for (i in object) {
    if (i === criteria.type && object[i][criteria.index] === criteria.value) {
      result.push(object);
    } else if (i === 'children' && object[i].length > 0) {
      for (j = 0; j < object[i].length; j++) {
        result = result.concat(searchAll(object[i][j], criteria));
      }
    }
  }

  return result;
}

console.log(searchAll(structure, {type: 'folder', index: 'name', value: 'name2'}));

编辑:链接到JSFiddle,因为它看起来像SO代码段停止递归,结果应该是正确的(带有你想要的数据的2个对象) https://jsfiddle.net/fswmxk7h/

答案 1 :(得分:0)

主要问题是,当您找到匹配项(return data;)时,您正在纾困并且不会附加到结果中。这是一个希望更简单和有效的版本。您还有一个问题,即您正在通过&#39;结果&#39;到递归,并将结果数组推到结果上,这不是你想要的。这对于你想要的风格(未经测试)来说是正确的:

var searchAll = function (data, searchFor, results) {
    results = results || [];
    if (data[searchFor.type] &&
        data[searchFor.type][searchFor.index].indexOf(searchFor.value) !== -1) {
        results.push(data); // now carry on an recurse children
    }
    if (data.children) {
        for (var i = 0; i < data.children.length; i++) {
            // use results arg to avoid array creation on recursion:
            searchAll(data.children[i], searchFor, results);
        }
    }
    return results;
};

searchAll(structure, {
    type: 'folder',
    index: 'name',
    value: 'name2'
});