фильтр-массив рекурсивно ищет родителей

У меня есть такой массив:

[
    {"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}
      ]}
  ]

Как я могу фильтровать на этом массиве, чтобы получить только имя объекта, в котором поле выбрано как [ ученик , школа , школа ] ?

Вывод должен быть массивом для имени объектов:

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

Я пробовал это с помощью lodash:

selected

Но это всегда возвращает корневые объекты, а не объекты, которые находятся внутри детей.

javascript,arrays,algorithm,filter,lodash,

0

Ответов: 7


3 принят

Можно просто перебирать и посмотреть , если разыскиваемое свойство trueявляется true, толкающим привести, если есть дети, итерация детей.

Это работает с 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);

То же самое с 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.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

Версия с 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);

И еще одна версия с 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.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>


1
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));


1

Вы можете использовать это решение ES6 для функционального программирования :

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);


1

Вы можете использовать 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);


0

Ну, вы должны учитывать сложность скрипта, который вы пытаетесь построить. Это вложенный линейный алгоритм (см. Https://en.wikipedia.org/wiki/Linear_search ), поскольку вам нужно прикоснуться к каждому элементу массива, чтобы создать новую структуру данных с selectedэлементами, что может быть очень медленным, если это размер массива увеличивается.

Вместо этого вы можете изменить метод, который переключает selectedсвойство, и скопировать этот «выбранный» объект в новый selectedElementsмассив.

Однако, если вы обязаны делать то, что вы просили, и вам нужны только результаты UNIQUE, проверьте это: