[英]How to filter an array of objects based on multiple properties in JavaScript/Typescript?
根据多个属性条件过滤对象数组并保留原始顺序的最佳方法是什么。 所以必须发生的是根据这两个条件过滤数组:
换句话说,只留下有效的和版本号最高的(版本号可以是任何)。
const arr = [
{ name: 'John', invalid: false, version: 1 },
{ name: 'John', invalid: false, version: 2 },
{ name: 'John', invalid: true, version: 1 },
{ name: 'John', invalid: true, version: 5 },
{ name: 'John', invalid: true, version: 2 },
{ name: 'Samuel', invalid: false, version: 1 },
{ name: 'Samuel', invalid: false, version: 2 },
{ name: 'Samuel', invalid: true, version: 1 },
];
至...
const arr = [
{ name: 'John', invalid: false, version: 2 },
{ name: 'Samuel', invalid: false, version: 2 }
];
提前致谢!
您可以使用Array.prototype.reduce来完成。
仅在以下情况下更新与特定name
对应的对象:
const data = [ { name: "John", invalid: false, version: 1 }, { name: "John", invalid: false, version: 2 }, { name: "John", invalid: true, version: 1 }, { name: "John", invalid: true, version: 5 }, { name: "John", invalid: true, version: 2 }, { name: "Samuel", invalid: false, version: 1 }, { name: "Samuel", invalid: false, version: 2 }, { name: "Samuel", invalid: true, version: 1 }, ]; const result = Object.values( data.reduce((acc, d) => { if (d.invalid) return acc; if (!acc[d.name] || d.version > acc[d.name].version) { acc[d.name] = d; } return acc; }, {}) ); console.log(result);
在 TS 中,您可以使用联合类型为有效和无效数据创建单独的类型。
type ValidData = { name: string; invalid: false; version: number };
type InvalidData = { name: string; invalid: true; version: number };
const data: (ValidData | InvalidData)[] = [
{ name: "John", invalid: false, version: 1 },
{ name: "John", invalid: false, version: 2 },
{ name: "John", invalid: true, version: 1 },
{ name: "John", invalid: true, version: 5 },
{ name: "John", invalid: true, version: 2 },
{ name: "Samuel", invalid: false, version: 1 },
{ name: "Samuel", invalid: false, version: 2 },
{ name: "Samuel", invalid: true, version: 1 },
];
const result = Object.values(
data.reduce((acc: { [name: string]: ValidData }, d) => {
if (d.invalid) return acc;
if (!acc[d.name] || d.version > acc[d.name].version) {
acc[d.name] = d;
}
return acc;
}, {})
);
console.log(result);
我建议分几个阶段执行此操作。 假设数组的顺序并不重要,您可以.sort
进行排序,使最新版本排在第一位,并跟踪您添加的内容,并过滤掉无效的内容。 像这样的东西:
function filterThing(thing) {
const added = new Set();
return thing.sort((a, b) => b.version - a.version).filter((item) => {
if (thing.invalid || added.has(thing.name)) {
return false;
}
added.add(thing.name);
return true;
}
}
如果您需要将项目按另一个顺序排列,则可以在此之后进行排序。 如果您需要保留项目的原始顺序,这是一个更复杂的算法。
您可以只使用查找表,这是在 O(n) 运行时。
基本上遍历数组一次,记住每个有效名称的最高版本,然后使用该表作为原始数组的过滤器。
const lookup = {} as Record<string, {name: string, version: number, invalid: boolean}>;
arr.forEach((it) => {
const stored = lookup[it.name];
if (stored) {
if (!it.invalid && it.version > stored.version) {
lookup[it.name] = it;
}
} else {
lookup[it.name] = it;
}
})
const filtered = arr.filter((it) => {
const stored = lookup[it.name];
const result = !it.invalid && it.version === stored.version;
if (result) { //if no duplicates wanted
delete lookup[it.name];
}
return result;
});
这是使用arr
数组的reduce()
方法的一种方法:
const ret = arr.reduce<typeof arr>((a, v) =>
v.invalid ? a :
!a.length || v.version > a[0].version ? [v] :
v.version < a[0].version ? a :
[...a, v],
[]);
我们从一个空数组[]
作为累加器a
开始,遍历arr
并按顺序检查每个值v
。 我们将通过附加每个非invalid
v
来构建v
, version
version
a
a
...
具体而言,以下是您给出的示例arr
的a
和v
的样子,并附有一些评论:
/*
a=[], v=John/false/1 => [John/false/1] // a empty, append v
a=[John/false/1], v=John/false/2 => [John/false/2] // v even newer, drop a and append v
a=[John/false/2], v=John/true/1 => [John/false/2] // v invalid, no change
a=[John/false/2], v=John/true/5 => [John/false/2] // v invalid, no change
a=[John/false/2], v=John/true/2 => [John/false/2] // v invalid, no change
a=[John/false/2], v=Samuel/false/1 => [John/false/2] // v old, no change
a=[John/false/2], v=Samuel/false/2 => [John/false/2; Samuel/false/2] // v new, append v
a=[John/false/2; Samuel/false/2], v=Samuel/true/1 =>
[John/false/2; Samuel/false/2] // v invalid, no change
*/
您可以看到我们以所需的顺序获得了所需的值:
console.log(ret);
/* [{
"name": "John",
"invalid": false,
"version": 2
}, {
"name": "Samuel",
"invalid": false,
"version": 2
}] */
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.