最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - filter array recursively looking for parents - Stack Overflow

programmeradmin0浏览0评论

I have an array like that:

[
    {"id":"one","name":"school", "selected": false, "children":[
      {"id":"1","name":"school", "selected": false},
      {"id":"2","name":"student", "selected": true},
      {"id":"3","name":"teacher", "selected": false}
      ]},
      {"name":"two","name":"school", "selected": false, "children":[
      {"id":"1","name":"school", "selected": true},
      {"id":"3","name":"teacher", "selected": false}
      ]},
      {"name":"three","name":"school", "selected": true, "children":[
      {"id":"1","name":"school", "selected": false},
      {"id":"2","name":"student", "selected": false}
      ]}
  ]

How I can filter on that array to get only the name of the object that has the field select as true?

The output should be an array for the name of objects:

[student, school, school]

I tried this using lodash:

_.filter(array, {selected: true}).map(function (division) {
            return array.name;
        });

But this always return the root objects, never the objects that are inside the children.

I have an array like that:

[
    {"id":"one","name":"school", "selected": false, "children":[
      {"id":"1","name":"school", "selected": false},
      {"id":"2","name":"student", "selected": true},
      {"id":"3","name":"teacher", "selected": false}
      ]},
      {"name":"two","name":"school", "selected": false, "children":[
      {"id":"1","name":"school", "selected": true},
      {"id":"3","name":"teacher", "selected": false}
      ]},
      {"name":"three","name":"school", "selected": true, "children":[
      {"id":"1","name":"school", "selected": false},
      {"id":"2","name":"student", "selected": false}
      ]}
  ]

How I can filter on that array to get only the name of the object that has the field select as true?

The output should be an array for the name of objects:

[student, school, school]

I tried this using lodash:

_.filter(array, {selected: true}).map(function (division) {
            return array.name;
        });

But this always return the root objects, never the objects that are inside the children.

Share Improve this question edited Oct 12, 2016 at 19:14 Pedro Henrique asked Oct 12, 2016 at 18:17 Pedro HenriquePedro Henrique 6392 gold badges9 silver badges27 bronze badges 3
  • You could use a basic for loop – Nick Tucci Commented Oct 12, 2016 at 18:23
  • 1 Just a note: children is the plural of child. – sabithpocker Commented Oct 12, 2016 at 18:35
  • @sabithpocker Or chilrens – guest271314 Commented Oct 12, 2016 at 19:05
Add a ment  | 

7 Answers 7

Reset to default 4

You could just iterate and look if the wanted property selected is true, the push to result, if there is a children, iterate the children.

This works with Array#forEach

var data = [{ "id": "one", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "two", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "three", "name": "school", "selected": true, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": false }] }],
    result = [];

data.forEach(function iter(o) {
    o.selected && result.push(o.name);
    (o.children || []).forEach(iter);
});
  
console.log(result);

The same with lodash _.forEach

var data = [{ "id": "one", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "two", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "three", "name": "school", "selected": true, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": false }] }],
    result = [];

_.forEach(data, function iter(o) {
    o.selected && result.push(o.name);
    _.forEach(o.children, iter);
});
  
console.log(result);
<script src="https://cdnjs.cloudflare./ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

A version with Array#reduce.

var data = [{ "id": "one", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "two", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "three", "name": "school", "selected": true, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": false }] }],
    result = data.reduce(function iter(r, o) {
        o.selected && r.push(o.name);
        return (o.children || []).reduce(iter, r);
    }, []);
  
console.log(result);

And another version with lodash _.reduce.

var data = [{ "id": "one", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "two", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] }, { "name": "three", "name": "school", "selected": true, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": false }] }],
    result = _.reduce(data, function iter(r, o) {
        o.selected && r.push(o.name);
        return _.reduce(o.children, iter, r);
    }, []);
  
console.log(result);
<script src="https://cdnjs.cloudflare./ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

array
   .reduce((a, i) => [...a, i, ...i.childs], [])//flatten array
   .filter(i => i.selected)//filter with selected===true
   .map(i => i.name));//map to name

console.log([{
  "id": "one",
  "name": "school",
  "selected": false,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": false
  }, {
    "id": "2",
    "name": "student",
    "selected": true
  }, {
    "id": "3",
    "name": "teacher",
    "selected": false
  }]
}, {
  "name": "two",
  "name": "school",
  "selected": false,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": true
  }, {
    "id": "3",
    "name": "teacher",
    "selected": false
  }]
}, {
  "name": "three",
  "name": "school",
  "selected": true,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": false
  }, {
    "id": "2",
    "name": "student",
    "selected": false
  }]
}].reduce((a, i) => [...a, i, ...i.childs], []).filter(i => i.selected).map(i => i.name));

You could use this functional programming style ES6 solution:

function sel(array) {
    return (array || []).reduce ( (acc, o) => 
        (o.selected ? acc.concat(o.name) : acc).concat(sel(o.childs)), [] );
}

  
function sel(array) {
    return (array || []).reduce ( (acc, o) => 
        (o.selected ? acc.concat(o.name) : acc).concat(sel(o.childs)), [] );
}
// Sample data
var array = [
    {"id":"one","name":"school", "selected": false, "childs":[
      {"id":"1","name":"school", "selected": false},
      {"id":"2","name":"student", "selected": true},
      {"id":"3","name":"teacher", "selected": false}
      ]},
      {"name":"two","name":"school", "selected": false, "childs":[
      {"id":"1","name":"school", "selected": true},
      {"id":"3","name":"teacher", "selected": false}
      ]},
      {"name":"three","name":"school", "selected": true, "childs":[
      {"id":"1","name":"school", "selected": false},
      {"id":"2","name":"student", "selected": false}
      ]}
  ];
// Extract
var result = sel(array);
// Ooutput result
console.log(result);

You can use Array.prototype.map(), Array.prototype.filter()

var arr = [{
  "id": "one",
  "name": "school",
  "selected": false,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": false
  }, {
    "id": "2",
    "name": "student",
    "selected": true
  }, {
    "id": "3",
    "name": "teacher",
    "selected": false
  }]
}, {
  "name": "two",
  "name": "school",
  "selected": false,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": true
  }, {
    "id": "3",
    "name": "teacher",
    "selected": false
  }]
}, {
  "name": "three",
  "name": "school",
  "selected": true,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": false
  }, {
    "id": "2",
    "name": "student",
    "selected": false
  }]
}];

var res = arr.map(el =>
  (el.selected && el || el.childs.filter(child =>
    child.selected
  )[0]).name
);

console.log(res);

Well, you should consider the plexity of the script you are trying to build. This is a nested linear algorithm (see https://en.wikipedia/wiki/Linear_search) since you have to touch every single element in the array to create the new data structure with the selected elements, which can be very slow if that array size increases.

What you might want to do instead, is to modify the method that toggles the selected property, and copy that 'selected' object to a new selectedElements array.

However, if you are required to do what you asked, and you only want UNIQUE results, check this out:

var data = [
  {"id":"one","name":"school", "selected": false, "childs":[
    {"id":"1","name":"school", "selected": false},
    {"id":"2","name":"student", "selected": true},
    {"id":"3","name":"teacher", "selected": false}
  ]},
  {"name":"two","name":"school", "selected": false, "childs":[
    {"id":"1","name":"school", "selected": true},
    {"id":"3","name":"teacher", "selected": false}
  ]},
  {"name":"three","name":"school", "selected": true, "childs":[
    {"id":"1","name":"school", "selected": false},
    {"id":"2","name":"student", "selected": false}
  ]}
],
    selectedElements = [];

data.map(function(row, i){
  if (row.selected) {
    if (selectedElements.indexOf(row.name) == - 1)
      selectedElements.push(row.name);
  }
  else{
    row.childs.map(function(childRow, ii) {
      if (childRow.selected) {
        if (selectedElements.indexOf(childRow.name) == - 1)
          selectedElements.push(childRow.name);
        }
    })
  }
});

console.log(selectedElements);

Add a line before your lodash _.filter

array = _.flatten(array.map(x => [x].concat(x.childs)))

so it will take the childs.

A classic recursive solution with arrow functions

var result = [];
var recursiveSearch = arr => {
  if (Array.isArray(arr)) {
    arr.forEach(x => {
    if (x.selected === true) result.push(x.name);
    if (Array.isArray(x.childs)) recursiveSearch(x.childs);
    });
  }
}
recursiveSearch(data);
console.log (result);
发布评论

评论列表(0)

  1. 暂无评论