Проблема фильтрации вложенных массивов JavaScript - PullRequest
0 голосов
/ 25 декабря 2018

Учитывая объект JavaScript, который представляет JSON, например, так -

[
    {
        "Id": "8868dfdd-9b4e-4bad-a4ce-ecae6a3cc828",
        "Name": "Company 1",
        "Locations": [
            {
                "Id": "bd017b9c-b62e-43aa-9f00-c164a855eed1",
                "Name": "Location 1",
                "Departments": [
                    {
                        "Id": "c9e4afe3-bbdb-474f-9062-2935025bfa2e",
                        "Name": "Department 1",
                        "Employees": [
                            {
                                "Id": "92c3a085-5712-422d-8b0f-922b57889c4f",
                                "Name": "Employee 1",
                                "Title": "FrontEnd Engineer",
                                "Location": "New York",
                                "Photo": ""
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

Я хочу отфильтровать эту структуру данных по имени сотрудника, учитывая, что может быть несколько компаний, местоположений, отделов.Вот моя попытка, но, очевидно, она не работает из-за моего понимания того, как Array.filter или Array.reduce работает.

filterContacts = search => {
    if (search.trim() === "") {
        this.setState({ filteredContacts: null, search: search });
    } else {
        let filteredArray = this.state.contacts.reduce((f, c) => {
            let clone = [];
            for (let i = 0; i < c.Locations.length; i++) {
                const l = c.Locations[i];
                for (let j = 0; j < l.Departments.length; j++) {
                    const d = l.Departments[j];
                    for (let k = 0; k < d.Employees.length; k++) {
                        const e = d.Employees[k];
                        if (e.Name.search(new RegExp(search, "i") > -1)) {
                            clone.push(l);
                        }
                    }
                }
            }
            return clone;
        }, []);
        this.setState({ filteredContacts: filteredArray, search: search });
    }
};

Любая помощь будет высоко ценится.Спасибо.

Ответы [ 2 ]

0 голосов
/ 25 декабря 2018

Вот еще одна короткая версия с использованием карты:

var rx=new RegExp(search,'i'),emp=[];
obj.map(c=>
 c.Locations.map(l=>
 l.Departments.map(d=>
 d.Employees.map(e=>
  {if(e.Name.match(rx)) emp.push(e)}
))));

search содержит шаблон поиска без учета регистра.Результат - emp, массив объектов сотрудника.

Как упомянуто выше, карта на самом деле не нужна и может быть заменена на forEach, но, на мой взгляд, ее легче написать, и она на самом деле не вызывает значительных дополнительных затрат.

Редактировать , на этот раз используя reduce():

Сейчас Рождество, и слишком много времени у меня на руках, я продолжаю играть дальше.Следующее решение отфильтровывает разыскиваемых сотрудников, не показывая их несоответствующих коллег и оставляя исходный массив без изменений:

const rd=(prop,fun)=>
             (a,el)=>{
var arr=el[prop].reduce(fun,[]);
if(arr.length){
  var r=Object.assign({},el);
// alternatively: use spread operator
// var r={...el};
  r[prop]=arr;a.push(r);}
return a;}

var rx=new RegExp('employee 1','i');

 var f=ma.reduce(
  rd('Locations',
  rd('Departments',
  rd('Employees',(a,e)=>{
     if(e.Name.match(rx))
      a.push(e);
     return a;}
,[]),[]),[]),[]);

f будет содержать массив, содержащий только те местоположения, отделы и сотрудников, где сотрудникибудет соответствовать регулярному выражению rx.

rd() - это функция генератора, возвращающая фактические функции фильтра, которые используются на трех разных reduce -уровнях.

Статическая функция Object.assign() - это простой способ создания мелкой копии объекта (аналогично методу slice() для массивов).

0 голосов
/ 25 декабря 2018

Когда вы используете:

 let clone = [];

в верхней части обратного вызова reduce(), вы выбрасываете аккумулятор - массив, который продолжает передаваться в цикле, который передается как f вваш код.Вы должны использовать один и тот же аккумулятор reduce каждый раз и вставлять его.В конце у вас будет массив всех значений:

let arr = [{"Id": "8868dfdd-9b4e-4bad-a4ce-ecae6a3cc828","Name": "Company 1","Locations": [{"Id": "bd017b9c-b62e-43aa-9f00-c164a855eed1","Name": "Location 1","Departments": [{"Id": "c9e4afe3-bbdb-474f-9062-2935025bfa2e","Name": "Department 1","Employees": [{"Id": "92c3a085-5712-422d-8b0f-922b57889c4f","Name": "Employee 1","Title": "FrontEnd Engineer","Location": "New York","Photo": ""}]}]}]}]

let emp = arr.reduce((f, obj) => {
  obj.Locations.forEach(location => 
    location.Departments.forEach(department => 
      f.push(...department.Employees.filter(emp => emp.Name == "Employee 1"))
    )
  )
  return f
}, []) // <-- this array will get passed to every loop as `f`

console.log(emp)

РЕДАКТИРОВАТЬ на основе комментария

Если вы хотите сохранить структуру, вы можете отфильтровать массивы по длине отфильтрованногомассив под ними.Вот пример с некоторыми дополнительными данными, которые видят работу по фильтрации. Первый полностью отфильтрован, третий имеет двух сотрудников с одинаковыми именами.По сути, он сохранит любой элемент, местоположение которого имеет отдел, в котором есть соответствующий сотрудник:

let arr = [
  {"Id": "someother","Name": "Company 2","Locations": [{"Id": "loc2Id","Name": "Location 2","Departments": [{"Id": "d2","Name": "Department 2","Employees": [{"Id": "emp","Name": "Employee 2","Title": "FrontEnd Engineer","Location": "New York","Photo": ""}]}]}]}, 
  {"Id": "8868dfdd-9b4e-4bad-a4ce-ecae6a3cc828","Name": "Company 1","Locations": [{"Id": "bd017b9c-b62e-43aa-9f00-c164a855eed1","Name": "Location 1","Departments": [{"Id": "c9e4afe3-bbdb-474f-9062-2935025bfa2e","Name": "Department 1","Employees": [{"Id": "92c3a085-5712-422d-8b0f-922b57889c4f","Name": "Employee 1","Title": "FrontEnd Engineer","Location": "New York","Photo": ""}]}]}]},
  {"Id": "someother","Name": "Company 2","Locations": [{"Id": "loc2Id","Name": "Location 2","Departments": [{"Id": "d2","Name": "Department 2","Employees": [{"Id": "emp","Name": "Employee 1","Title": "FrontEnd Engineer","Location": "New York","Photo": ""}, {"Id": "emp","Name": "Employee 1","Title": "FrontEnd Engineer 2","Location": "New York","Photo": ""}]}]}]}, 
]


let f = []
let emp = arr.filter(arr => 
  arr.Locations.filter(location => 
    location.Departments.filter(department => {
      let emp = department.Employees.filter(emp => emp.Name == "Employee 1")
      return emp.length ? emp: false 
    }
    ).length
  ).length
) // <-- this array will get passed to every loop as `f`

console.log(emp)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...