给出一个表示JSON的JavaScript对象-
[
{
"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 });
}
};
任何帮助将不胜感激。谢谢。
答案 0 :(得分:2)
使用时:
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)
答案 1 :(得分:1)
这是另一个使用map的简短版本:
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
,这是一组雇员对象。
如上所述,map并不是真正必要的,可以用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()
方法)。