如何在JavaScript中的flatMap数组方法中获取累加器(flatMap vs reduce)



有一个初始数组需要同时映射和过滤:

let data = [
{
"id": 1,
"parentId": null,
"dxId": "1_id",
"dxParentId": null,
"defName": "group1"
},
{
"id": 12,
"parentId": null,
"dxId": "12_id",
"dxParentId": null,
"defName": "группа3"
},
{
"id": 8,
"parentId": 1,
"dxId": "1_id/13",
"dxParentId": "1_id",
"defName": "group4"
},
{
"id": 5,
"parentId": 1,
"dxId": "1_id/20",
"dxParentId": "1_id",
"defName": "user1"
},
{
"id": 5,
"parentId": 1,
"dxId": "1_id/20",
"dxParentId": "12_id",
"defName": "user1"
},
];

我根据parenside属性的存在进行筛选,并收集结果字符串数组(而不是对象的初始数组(。

最初我是通过reduce方法做的:

resultArr = data.reduce((filtered, obj) => {
if(  obj.dx_parentId !== null) {
if(!(filtered.includes(obj.dxParentId)))  {
filtered.push(obj.dxParentId);
}
}
return filtered;
}, []);
console.log(resultArr , 'result'); // ['1_id', '12_id'] 'result'

然后我自己发现这可以用flatMap数组方法来完成

resultArr =  data.flatMap((obj) =>  obj.dxParentId !== null ? [obj.dxParentId] : []);
console.log(resultArr , 'result'); //['1_id', '1_id', '12_id'] 'result'

如果您注意到,在reduce的情况下,我使用过滤(累积数组(我使用includes进行额外检查,并得到所需的结果。

问题是如何通过flatMap进行同样的操作?是否可以访问每次迭代的累积结果?

此外:有人能告诉我在优化方面,用什么更好地解决这个问题吗?mb for Each?提前感谢

您无法访问flatMap中正在构建的数组。在映射以及具有平坦化的映射中,回调应该返回一个仅依赖于特定项的值。

对于这样的命令式算法,您可能根本不想使用reduce

const resultArr = [];
for (const obj of data) {
if (obj.dxParentId !== null) {
if (!resultArr.includes(obj.dxParentId)) {
filtered.push(obj.dxParentId);
}
}
}
console.log(resultArr, 'result');

然而,要从数组中获得唯一值,有一种更好(更简单、更高效(的方法:

const resultArr = Array.from(new Set(data.map(obj => obj.dxParentId).filter(id => id !== null)));
console.log(resultArr, 'result');

因此,虽然您不能在构建阵列平面图时查看它正在构建,但您可以在平面图之外创建一个对象,并使用它来跟踪您是否添加了哪些id。

const seen = {};
const resultArr = data.flatMap((obj) => {
const id = obj.dxParentId;
if (id in seen) return [];
if (id !== null) {
seen[id] = true;
return [id];
}
return [];
});
console.log(resultArr, "result"); //['1_id', '1_id', '12_id'] 'result'

就时间和空间复杂性而言,这种解决方案要快得多,但占用的空间要大得多(在大多数情况下,这是一个很好的折衷方案(。

Array.include((遍历整个数组,时间复杂度为O(n(。键入对象具有恒定的时间复杂性,但构建对象是O(n(空间。

在我看来,最好的解决方案是将对象的即时查找与reduce的作用域相结合。

const resultArr = data.reduce(
(acc, obj) => {
const id = obj.dxParentId;
const { seen, filtered } = acc;
if (id in seen) return acc;
if (id !== null) {
seen[id] = true;
filtered.push(id);
}
return acc;
},
{ seen: {}, filtered: [] }
).filtered;
console.log(resultArr, "result"); // ['1_id', '12_id'] 'result'

该解决方案具有与平面图相同的时间和空间复杂性,但只要reduce方法完成,所看到的对象就有资格进行垃圾收集,因此这些潜在的空间问题就不那么重要了。

最新更新