简体   繁体   English

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

[英]How to get accumulator in flatMap array methode in JavaScript(flatmap vs reduce)?

There is an initial array that needs to be mapped and filtered at the same time:有一个初始数组需要同时映射和过滤:

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"
        },
    ];

I filter by the presence of the parentide property, and collect the resulting array of strings (not the initial array of objects).我通过 parentide 属性的存在进行过滤,并收集结果字符串数组(不是初始对象数组)。

originally I did it through reduce methode:最初我是通过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'

then I discovered for myself that this can be done with the flatMap array method然后我自己发现这可以用 flatMap 数组方法来完成

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

If you notice that in the case of reduce I use filtered (accumulating array) I do an additional check using includes and I get the result that I need.如果您注意到在减少的情况下我使用过滤(累加数组) ,我会使用包含进行额外检查,我会得到我需要的结果。

The question is how to do the same it via flatMap?问题是如何通过 flatMap 做同样的事情? is it possible to access the accumulating result at each iteration?是否可以在每次迭代时访问累积结果?

Additionally: can someone tell me what is better to use to solve this case, in terms of optimization?另外:有人可以告诉我在优化方面用什么更好地解决这种情况? mb forEach? mb forEach? thanks in advance提前致谢

You cannot access the array that is being built in flatMap .您无法访问在flatMap中构建的数组。 In mapping, and also mapping-with-flattening, the callback is supposed to return a value that depends only on the particular item.在映射以及带扁平化的映射中,回调应该返回一个仅取决于特定项目的值。

You might simple not want to use reduce at all for an imperative algorithm like this:对于这样的命令式算法,您可能根本不想使用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');

However, to get unique values from an array there is a much better (simpler and more efficient) way:但是,要从数组中获取唯一值,有一种更好(更简单、更有效)的方法:

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

So while you can't view the array flatmap is building while its building it, you can create an object just outside of flatmap and use it to track which ids you've added or not.因此,虽然您无法在构建阵列平面图时查看它正在构建,但您可以在平面图之外创建一个 object 并使用它来跟踪您添加或未添加的 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'

As far as time and space complexity goes this solution is much faster, but takes up much more space (in most cases that's a good tradeoff).就时间和空间复杂性而言,此解决方案要快得多,但占用更多空间(在大多数情况下这是一个很好的权衡)。

Array.include() traverses the entire array and has a time complexity of O(n). Array.include() 遍历整个数组,时间复杂度为 O(n)。 key in object has a constant time complexity, but building the object is O(n) space. object 中的关键具有恒定的时间复杂度,但构建 object 是 O(n) 空间。

In my opinion the best possible solution would be combining the instant lookup of an object with the scoping of reduce.在我看来,最好的解决方案是将 object 的即时查找与 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'

This solution has the same time and space complexity as the flatmap, but the seen object becomes eligible for garbage collection as soon as the reduce method finishes so those potential space issues aren't as large of a concern.此解决方案具有与平面图相同的时间和空间复杂性,但看到的 object 在 reduce 方法完成后就可以进行垃圾收集,因此这些潜在的空间问题并不那么重要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM