[英]How to filter an outer array based on an inner array?
我有一个像这样的json,我想获取几乎所有具有所选属性等于true的服务的区域。
{
"areas": [
{
"name": "area 1",
"services": [
{
"label": "srv 1",
"selected": true
},
{
"label": "srv 2",
"selected": false
},
{
"label": "srv 3",
"selected": false
},
{
"label": "srv 4",
"selected": true
}
]
},
{
"name": "area 2",
"services": [
{
"label": "srv 1",
"selected": false
},
{
"label": "srv 2",
"selected": true
},
{
"label": "srv 3",
"selected": false
},
{
"label": "srv 4",
"selected": false
}
]
},
{
"name": "area 3",
"services": [
{
"label": "srv 1",
"selected": false
},
{
"label": "srv 2",
"selected": false
},
{
"label": "srv 3",
"selected": false
}
]
},
{
"name": "area 4",
"services": [
{
"label": "srv 1",
"selected": true
},
{
"label": "srv 2",
"selected": false
},
{
"label": "srv 3",
"selected": true
}
]
}
]
}
结果必须仅包含具有所选属性等于true的服务的区域,并且必须指出该区域而不更改原始数组。
有了这个代码
const result = areas.filter(area =>
services.some(srv => srv.selected == true)
);
我获得了所有区域,但是在这些区域内,我具有所有服务(选择为true和选择为false)。
这是我想要的:
{
"areas": [
{
"name": "area 1",
"services": [
{
"label": "srv 1",
"selected": true
},
{
"label": "srv 4",
"selected": true
}
]
},
{
"name": "area 2",
"services": [
{
"label": "srv 2",
"selected": true
}
]
},
{
"name": "area 4",
"services": [
{
"label": "srv 1",
"selected": true
},
{
"label": "srv 3",
"selected": true
}
]
}
]
}
谢谢
为避免input.areas
原始对象,请map
每个input.areas
项,以将其变成一个对象,该对象在其services
仅包含true selected
的,然后根据services
属性中是否包含任何项进行filter
:
const transform = (input) => input.areas .map(({ name, services }) => ({ name, services: services.filter(({ selected }) => selected) })) .filter(({ services }) => services.length); const input = { "areas": [ { "name": "area 1", "services": [ { "label": "srv 1", "selected": true }, { "label": "srv 2", "selected": false }, { "label": "srv 3", "selected": false }, { "label": "srv 4", "selected": true } ] }, { "name": "area 2", "services": [ { "label": "srv 1", "selected": false }, { "label": "srv 2", "selected": true }, { "label": "srv 3", "selected": false }, { "label": "srv 4", "selected": false } ] }, { "name": "area 3", "services": [ { "label": "srv 1", "selected": false }, { "label": "srv 2", "selected": false }, { "label": "srv 3", "selected": false } ] }, { "name": "area 4", "services": [ { "label": "srv 1", "selected": true }, { "label": "srv 2", "selected": false }, { "label": "srv 3", "selected": true } ] } ] }; console.log(transform(input));
您可以减少数组,仅过滤过滤后services
包含某些项目的部分。
var data = { areas: [{ name: "area 1", services: [{ label: "srv 1", selected: true }, { label: "srv 2", selected: false }, { label: "srv 3", selected: false }, { label: "srv 4", selected: true }] }, { name: "area 2", services: [{ label: "srv 1", selected: false }, { label: "srv 2", selected: true }, { label: "srv 3", selected: false }, { label: "srv 4", selected: false }] }, { name: "area 3", services: [{ label: "srv 1", selected: false }, { label: "srv 2", selected: false }, { label: "srv 3", selected: false }] }, { name: "area 4", services: [{ label: "srv 1", selected: true }, { label: "srv 2", selected: false }, { label: "srv 3", selected: true }] }] }, result = data.areas.reduce((r, o) => { var services = o.services.filter(({ selected }) => selected); if (services.length) r.push(Object.assign({}, o, { services })); return r; }, []); console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
您可以使用过滤器两次
const res = data.areas.filter(e => { e.services = e.services.filter(s => s.selected); return e.services.length; }); console.log(res);
<script> const data = { "areas": [ { "name": "area 1", "services": [ { "label": "srv 1", "selected": true }, { "label": "srv 2", "selected": false }, { "label": "srv 3", "selected": false }, { "label": "srv 4", "selected": true } ] }, { "name": "area 2", "services": [ { "label": "srv 1", "selected": false }, { "label": "srv 2", "selected": true }, { "label": "srv 3", "selected": false }, { "label": "srv 4", "selected": false } ] }, { "name": "area 3", "services": [ { "label": "srv 1", "selected": false }, { "label": "srv 2", "selected": false }, { "label": "srv 3", "selected": false } ] }, { "name": "area 4", "services": [ { "label": "srv 1", "selected": true }, { "label": "srv 2", "selected": false }, { "label": "srv 3", "selected": true } ] } ] } </script>
你可以这样做
obj.areas.filter(area =>
area.services = area.services.filter(srv => srv.selected == true)
);
这应该足够了,您基本上可以使用Array#filter
的组合。
const filterBySelectedServices = list => list .map(area => Object.assign({}, area, { services: area.services.filter(service => service.selected), })) .filter(area => area.services.length); const data = { "areas": [ { "name": "area 1", "services": [ { "label": "srv 1", "selected": true }, { "label": "srv 2", "selected": false }, { "label": "srv 3", "selected": false }, { "label": "srv 4", "selected": true } ] }, { "name": "area 2", "services": [ { "label": "srv 1", "selected": false }, { "label": "srv 2", "selected": true }, { "label": "srv 3", "selected": false }, { "label": "srv 4", "selected": false } ] }, { "name": "area 3", "services": [ { "label": "srv 1", "selected": false }, { "label": "srv 2", "selected": false }, { "label": "srv 3", "selected": false } ] }, { "name": "area 4", "services": [ { "label": "srv 1", "selected": true }, { "label": "srv 2", "selected": false }, { "label": "srv 3", "selected": true } ] } ] }; console.log('result', filterBySelectedServices(data.areas));
您可以使用reduce
和filter
并且只接受那些在过滤后服务中包含某些项目的元素
let data = {"areas": [{"name": "area 1","services": [{"label": "srv 1","selected": true},{"label": "srv 2","selected": false},{"label": "srv 3","selected": false},{"label": "srv 4","selected": true}]},{"name": "area 2","services": [{"label": "srv 1","selected": false},{"label": "srv 2","selected": true},{"label": "srv 3","selected": false},{"label": "srv 4","selected": false}]},{"name": "area 3","services": [{"label": "srv 1","selected": false},{"label": "srv 2","selected": false},{"label": "srv 3","selected": false}]},{"name": "area 4","services": [{"label": "srv 1","selected": true},{"label": "srv 2","selected": false},{"label": "srv 3","selected": true}]}]} let final = data.areas.reduce((op, inp) => { let services = inp.services.filter( ({selected}) => selected ) if(services.length) op.push({...inp, services}) return op },[]) console.log(final)
您可以使用reduce
filter
内部数组,而无需更改输入
const input={"areas":[{"name":"area 1","services":[{"label":"srv 1","selected":true},{"label":"srv 2","selected":false},{"label":"srv 3","selected":false},{"label":"srv 4","selected":true}]},{"name":"area 2","services":[{"label":"srv 1","selected":false},{"label":"srv 2","selected":true},{"label":"srv 3","selected":false},{"label":"srv 4","selected":false}]},{"name":"area 3","services":[{"label":"srv 1","selected":false},{"label":"srv 2","selected":false},{"label":"srv 3","selected":false}]},{"name":"area 4","services":[{"label":"srv 1","selected":true},{"label":"srv 2","selected":false},{"label":"srv 3","selected":true}]}]} const areas = input.areas.reduce((r, a) => { const services = a.services.filter(s => s.selected) if(services.length) r.push({ ...a, services }); return r }, []) console.log({ areas })
尝试这样的事情:
const data = { "areas": [{ "name": "area 1", "services": [{ "label": "srv 1", "selected": true }, { "label": "srv 2", "selected": false }, { "label": "srv 3", "selected": false }, { "label": "srv 4", "selected": true } ] }, { "name": "area 2", "services": [{ "label": "srv 1", "selected": false }, { "label": "srv 2", "selected": true }, { "label": "srv 3", "selected": false }, { "label": "srv 4", "selected": false } ] }, { "name": "area 3", "services": [{ "label": "srv 1", "selected": false }, { "label": "srv 2", "selected": false }, { "label": "srv 3", "selected": false } ] }, { "name": "area 4", "services": [{ "label": "srv 1", "selected": true }, { "label": "srv 2", "selected": false }, { "label": "srv 3", "selected": true } ] } ] } const res = data.areas.map(x => { // Destructure the name and services from the current callback object const { name, services } = x; // Now filter the services object where the .selected property is set to true const filteredServices = services.filter(x => x.selected); if (filteredServices.length) { // Project your desired object return { name: name, services: filteredServices } } }) // Also filter for empty services .filter(x => x); console.log(res);
您可以在过滤器的回调中进行过滤,如下所示:
let data = {"areas": [{"name": "area 1", "services": [{"label": "srv 1", "selected": true}, {"label": "srv 2", "selected": false}, {"label": "srv 3", "selected": false}, {"label": "srv 4", "selected": true}]}, {"name": "area 2", "services": [{"label": "srv 1", "selected": false}, {"label": "srv 2", "selected": true}, {"label": "srv 3", "selected": false}, {"label": "srv 4", "selected": false}]}, {"name": "area 3", "services": [{"label": "srv 1", "selected": false}, {"label": "srv 2", "selected": false}, {"label": "srv 3", "selected": false}]}, {"name": "area 4", "services": [{"label": "srv 1", "selected": true}, {"label": "srv 2", "selected": false}, {"label": "srv 3", "selected": true}]}]}; const result = data.areas.filter(area => { // filter area services let selectedServices = area.services.filter(service => { return service.selected; }); // If the area has selected services if (selectedServices.length) { // Save the selected services to area.services area.services = selectedServices; return true; } else { // Do not select the area return false; } }); console.log(result);
但是,正如@CodeManiac指出的那样,这将使原始数组发生突变,如果要保留它,则使用reduce : data.areas.reduce()
而不是data.areas.filter()
在完成第一次过滤之后,可以按以下步骤过滤每个索引中的服务:
result.forEach((item)=>{
item.services = item.services.filter((service)=>service.selected==true);
})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.