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 operator
will expand element
and then filtered subElements
will override the subElements
in element.
Spread operator
将展开element
然后过滤subElements
将覆盖subElements
in 元素。
回答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
subElements
value 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 this
inside 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
更正确