Как я могу использовать Lodash / JS для рекурсивной фильтрации вложенных объектов? - PullRequest
0 голосов
/ 06 сентября 2018

У меня есть массив с объектами неизвестной глубины, как это

var objects = [{
    id: 1,
    name: 'foo'
}, {
    id: 2,
    name: 'bar',
    childs: [{
        id: 3,
        name: 'baz',
        childs: [{
            id: 4,
            name: 'foobar'
        }]
    }]
}];

Я бы хотел иметь возможность фильтровать определенный дочерний объект по его идентификатору.

В настоящее время я использую этот маленький сценарий lodash (от этот вопрос ), но он работает только с объектами не более одного уровня. Таким образом, поиск id: 1 и id: 2 будет работать нормально, тогда как поиск id: 3 или id: 4 вернет undefined.

function deepFilter(obj, search) {
    return _(obj)
        .thru(function(coll) {
            return _.union(coll, _.map(coll, 'children'));
        })
        .flatten()
        .find(search);
}

Немного JSfiddle.

Ответы [ 4 ]

0 голосов
/ 06 сентября 2018

Вы можете иметь рекурсивную функцию и проверять ребенка

var objects = [{
  id: 1,
  name: 'foo'
}, {
  id: 2,
  name: 'bar',
  childs: [{
    id: 3,
    name: 'baz',
    childs: [{
      id: 4,
      name: 'foobar'
    }]
  }]
}];
let tempArray = [];


function doRecursiveSearch(obj, id) {

  obj.forEach(function(item) {
    console.log(item)
    if (item.id === id) {
      tempArray.push(item)
    } else {
      if (item.childs && Array.isArray(item.childs)) {
        console.log(item)
        doRecursiveSearch(item.childs, id)
      }
    }

  })
}
doRecursiveSearch(objects, 4)
console.log(tempArray)
0 голосов
/ 06 сентября 2018

Вы можете сделать это рекурсивно так:

function deepFind(arr, search) {
    for(var obj of arr) {
        if(search(obj)) {
            return obj;
        }
        if(obj.childs) {
            var deepResult = deepFind(obj.childs, search);
            if(deepResult) {
                return deepResult;
            }
        }
    }
    return null;
}

Тогда используйте это так:

var result = deepFind(objects, function(obj) {
    return obj.id === myId;
});

Пример:

function deepFind(arr, search) {
    for(var obj of arr) {
        if(search(obj)) {
            return obj;
        }
        if(obj.childs) {
            var deepResult = deepFind(obj.childs, search);
            if(deepResult) {
                return deepResult;
            }
        }
    }
    return null;
}

var objects = [{id: 1,name: 'foo'}, {id: 2,name: 'bar',childs: [{id: 3,name: 'baz',childs: [{id: 4,name: 'foobar'}]}]}];

console.log("ID 1:", deepFind(objects, obj => obj.id === 1));
console.log("ID 4:", deepFind(objects, obj => obj.id === 4));
console.log("ID 7:", deepFind(objects, obj => obj.id === 7));
0 голосов
/ 06 сентября 2018

Вы можете использовать итеративный и рекурсивный подход.

function find(id, array) {
    var result;
    array.some(o => o.id === id && (result = o) || (result = find(id, o.children || [])));
    return result;
}

var objects = [{ id: 1, name: 'foo' }, { id: 2, name: 'bar', children: [{ id: 3, name: 'baz', children: [{ id: 4, name: 'foobar' }] }] }];

console.log(find(1, objects));
console.log(find(2, objects));
console.log(find(3, objects));
console.log(find(4, objects));
.as-console-wrapper { max-height: 100% !important; top: 0; }
0 голосов
/ 06 сентября 2018

Вам необходимо вызвать функцию рекурсивно, чтобы нацелить дочерний объект. Попробуйте следовать

Итерируйте по массиву и для каждого объекта проверьте, найден ли id. Если да, прервите и верните результат, иначе продолжайте поиск в child (если существует).

Подход 1: Обходит ветку дерева по ветвям

Используя этот подход, сначала код переходит от первого элемента к последнему дочернему элементу, затем второй элемент - к последнему дочернему элементу и т. Д.

var objects = [{id: 1,name: 'foo'}, {id: 2,name: 'bar',childs: [{id: 3,name: 'baz',childs: [{id: 4,name: 'foobar'}]}]}];

function findObject(arr, id) {
  var result;
  for (let i = 0 ; i < arr.length; i++) {
    if(arr[i].id === id) {
      result = arr[i];
      break;
    }
    if(arr[i].childs) {
      result = findObject(arr[i].childs, id);
      if(result) break;
    }
  }
  return result;
}

console.log(findObject(objects, 4));

Подход 2. Обходит глубину дерева по глубине

Используя этот подход, сначала код проходит элементы первого уровня, затем элементы второго уровня и т. Д.

var objects = [{id: 1,name: 'foo'}, {id: 2,name: 'bar',childs: [{id: 3,name: 'baz',childs: [{id: 4,name: 'foobar'}]}]}];

function findObject(arr, id) {
  var result;
  var children = [];
  for (let i = 0 ; i < arr.length; i++) {
    if(arr[i].id === id) {
      result = arr[i];
      break;
    }
    if(arr[i].childs) {
      children = [...children, ...arr[i].childs];
    }
  }
  if(!result && children.length) {
    result = findObject(children, id);
  }
  return result;
}

console.log(findObject(objects, 4));
...