Javascript 使用基于嵌套值的数组过滤对象数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38375646/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Filtering array of objects with arrays based on nested value
提问by bartosz.baczek
I am trying to filter an array, based on some nested object. I prepared some Fiddle
我正在尝试基于某个嵌套对象过滤数组。我准备了一些小提琴
Input array looks like this:
输入数组如下所示:
let arrayOfElements =
[
{
"name": "a",
"subElements":
[
{"surname": 1},
{"surname": 2}
]
},
{
"name": "b",
"subElements":
[
{"surname": 3},
{"surname": 1}
]
},
{
"name": "c",
"subElements":
[
{"surname": 2},
{"surname": 5}
]
}
];
I want the output for this case, to look like this:
我希望这种情况下的输出如下所示:
let filteredArray =
[
{
"name": "a",
"subElements":
[
{"surname": 1}
]
},
{
"name": "b",
"subElements":
[
{"surname": 1}
]
}
];
I am using this formula to do that:
我正在使用这个公式来做到这一点:
let filteredArray = arrayOfElements.filter((element) => element.subElements.some((subElement) => subElement.surname === 1));
Output is almost good, but it returns objects with all objects with surnames (better check that fiddle :D), instead of cutting them away. How can i improve the filtering ?
输出几乎不错,但它返回包含所有带姓氏的对象的对象(最好检查小提琴:D),而不是将它们切掉。如何改进过滤?
回答by Andrew Eisenberg
After you call filter, you need to pipe the results to map, like this:
调用 后filter,您需要将结果通过管道传送到map,如下所示:
let filteredArray = arrayOfElements
.filter((element) =>
element.subElements.some((subElement) => subElement.surname === 1))
.map(element => {
let newElt = Object.assign({}, element); // copies element
return newElt.subElements.filter(subElement => subElement.surname === '1');
});
I am assuming here that you don't want to manipulate the original array. So, I am using Object.assign.
我在这里假设您不想操作原始数组。所以,我正在使用 Object.assign。
回答by Mohak Londhe
let filteredArray = arrayOfElements
.filter((element) =>
element.subElements.some((subElement) => subElement.surname == 1))
.map(element => {
return Object.assign({}, element, {subElements : element.subElements.filter(subElement => subElement.surname == 1)});
});
回答by Nitesh Ranjan
This way you can go as deep as you want in an array and filter elements at any level,
通过这种方式,您可以在任何级别的数组中尽可能深入并过滤元素,
arrayOfElements.map((element) => {
return {...element, subElements: element.subElements.filter((subElement) => subElement.surname === 1)}
})
Spread operatorwill expand elementand then filtered subElementswill override the subElementsin element.
Spread operator将展开element然后过滤subElements将覆盖subElementsin 元素。
回答by Sarvar Nishonboev
Just improved the answers above
刚刚改进了上面的答案
let elements =
[
{
"name": "a",
"subElements":
[
{"surname": 1},
{"surname": 2}
]
},
{
"name": "b",
"subElements":
[
{"surname": 3},
{"surname": 1}
]
},
{
"name": "c",
"subElements":
[
{"surname": 2},
{"surname": 5}
]
}
];
var value = 1;
var filteredArray = elements
.filter(element => element.subElements
.some(subElement => subElement.surname === value)
)
.map(element => {
let n = Object.assign({}, element, {'subElements': element.subElements.filter(
subElement => subElement.surname === value
)})
return n;
})
console.log(filteredArray)
回答by Praveenkarthi
Try this solution:
试试这个解决方案:
data_filter = arrayOfElements.filter(function (element) {
return element.subElements.some( function (subElement) {
return subElement.surname === surname
});
});
回答by Himanshu Tyagi
function display_message() {
let arrayOfElements = [{
"name": "a",
"subElements": [{
"surname": 1
}, {
"surname": 2
}]
}, {
"name": "b",
"subElements": [{
"surname": 3
}, {
"surname": 1
}]
}, {
"name": "c",
"subElements": [{
"surname": 2
}, {
"surname": 5
}]
}];
// console.log(arrayOfElements);
var surname = 1;
let filteredArray = arrayOfElements.filter((element) => element.subElements.some((subElement) => subElement.surname === surname));
for(var data in filteredArray){
filteredArray[data].subElements = {"surname": surname};
}
console.log(filteredArray);
}
<input type="button" onclick="display_message();" value="click"/>
回答by Rajesh
You can make it generic as well:
您也可以使其通用:
Logic
逻辑
- Find all distinct surnames and loop over them
- Filter every object to check if surnames exists. If yes, copy object using Object.assignand set
subElementsvalue to filtered list. - Create a temp array to hold all similar objects and push copied object to it.
- Push this array to final array on every iteration of distinct surname.
- 找到所有不同的姓氏并遍历它们
- 过滤每个对象以检查姓氏是否存在。如果是,请使用Object.assign复制对象并将
subElements值设置为过滤列表。 - 创建一个临时数组来保存所有相似的对象并将复制的对象推送到它。
- 在不同姓氏的每次迭代中将此数组推送到最终数组。
Sample
样本
let arrayOfElements=[{name:"a",subElements:[{surname:1},{surname:2}]},{name:"b",subElements:[{surname:3},{surname:1}]},{name:"c",subElements:[{surname:2},{surname:5}]}];
let distinct_surnames = [];
arrayOfElements.forEach(function(el) {
el.subElements.forEach(function(s) {
if (distinct_surnames.indexOf(s.surname) < 0) distinct_surnames.push(s.surname)
});
})
let result = [];
distinct_surnames.forEach(function(sn) {
let inter = [];
arrayOfElements.forEach(function(el) {
let f = el.subElements.filter(function(sub) {
return sub.surname === sn;
});
if (f.length > 0) {
let _tmp = Object.assign({}, el);
_tmp.subElements = f;
inter.push(_tmp);
}
});
result.push(inter);
})
console.log(result)
Note:Arrow functions are used to keep the reference of this. If you are not using thisinside function, you can use normal functions as well.
注意:箭头函数用于保持this. 如果不使用this内部函数,也可以使用普通函数。
回答by Ilya Alexeev
let filteredArray = arrayOfElements
.filter((element) =>
element.subElements.some((subElement) => subElement.surname === 1))
.map(element => {
let newElt = Object.assign({}, element); // copies element
newElt.subElements = newElt.subElements.filter(subElement => subElement.surName === '1');
return newElt;
});
is more correctly
更正确

