使用Array.prototype.filter过滤嵌套的子对象

时间:2016-05-20 07:06:18

标签: javascript arrays

我有一个类似于以下代码块的对象数组:

var arr = [
	{
    	text: 'one',
        children: [
        	{
            	text: 'a',
                children: [
                	{
                        text: 'something'
                    }
                ]
            },
            {
            	text: 'b'
            },
            {
            	text: 'c'
            }
        ]
    },
    {
    	text: 'two'
    },
    {
    	text: 'three'
    },
    {
    	text: 'four'
    }
];

在上面的结构中,我想搜索text属性中的字符串,我需要对所有children执行此搜索。

例如,如果我搜索something,结果应该是以下形式的对象数组:

[
	{
        children: [
        	{
                children: [
                	{
                        text: 'something'
                    }
                ]
            }
        ]
    }
];

请注意,与输入字符串text不匹配的所有something属性都已删除。

我使用Array.prototype.filter提出了以下代码块。但是,我仍然可以在结果中看到额外的属性:

function search(arr, str) {
    return arr.filter(function(obj) {
    	if(obj.children && obj.children.length > 0) {
          return search(obj.children, str);
        }
        
	if(obj.text === str) {
          return true;
        }
        else {
          delete text;
          return false;
        }
    });
}

以下是小提琴链接:https://jsfiddle.net/Lbx2dafg/

我做错了什么?

2 个答案:

答案 0 :(得分:4)

我建议使用Array#forEach,因为过滤器返回一个数组,这是必需的,但不适用于此目的,因为它会返回所有带有它的子项。

此提案使用wantes项textchildren从找到的项目中生成一个新数组。

解决方案以迭代和递归方式工作。它会查找搜索字符串的所有出现。



function filter(array, search) {
    var result = [];
    array.forEach(function (a) {
        var temp = [],
            o = {},
            found = false;

        if (a.text === search) {
            o.text = a.text;
            found = true;
        }
        if (Array.isArray(a.children)) {
            temp = filter(a.children, search);
            if (temp.length) {
                o.children = temp;
                found = true;
            }
        }
        if (found) {
            result.push(o);
        }
    });
    return result;
}

var array = [{ text: 'one', children: [{ text: 'a', children: [{ text: 'something' }] }, { text: 'b' }, { text: 'c' }] }, { text: 'two' }, { text: 'three' }, { text: 'four' }];

console.log(filter(array, 'something'));




答案 1 :(得分:1)

你的函数search返回一个包含来自“parent”级别的对象的数组,这就是你“仍然在结果中看到额外属性”的原因。其次,这一行{ {1}}不会删除对象或对象属性 - 它应该是delete text;
这是使用其他delete obj.text;函数的解决方案:

Array.map

输出:

function search(arr, str) {
    return arr.filter(function(obj) {
        if (obj.text !== str) {
           delete obj.text;
        }
        if (obj.children && obj.children.length > 0) {
           return search(obj.children, str);
        }

        if (obj.text === str) {
           return true;
        } else {
           delete obj.text;
           return false;
        }
    });
}

var result = search(arr, 'something').map(function(v) {  // filtering empty objects
   v['children'] = v['children'].filter((obj) => Object.keys(obj).length);
   return {'children':v['children'] };
});
console.log(JSON.stringify(result,0,4));

complete-callback