【问题标题】:Is there another way to solve this forEach problem using map, filter, reduce...?是否有另一种方法可以使用 map、filter、reduce 来解决这个 forEach 问题......?
【发布时间】:2019-04-07 20:44:00
【问题描述】:

如果我有两个这样的对象数组

const x = [{id: 1, a: 5}, {id: 2, a:10}, {id: 3, a: 12}];

const y = [{id: 4, a: 0}, {id: 2, a: 0}, {id: 3, a: 0}];

输出应该是一个代表y的新数组 但是经过一些修改,如果 y 中的一个项目有一个 id 匹配 x 中的一个项目,a 的值应该与 x 相同,所以输出应该是

[{id: 4, a: 0}, {id: 2, a: 10}, {id: 3, a: 12}]

这是我的解决方案

const z = [...y];
z.forEach(el => x.map(ele =>  el.a = el.id === ele.id ? ele.a : el.a));

这是我在项目中所做的一个简单实现,我关心性能,我看到克隆数组 z = [...y] 的步骤可能很昂贵,所以我正在寻找一个使用返回新函数的解决方案数组map, filter, reduce...,

我尝试了嵌套的 mapfilterfind ...但我以复杂的解决方案结束,那么是否有其他解决方案可以同时更高效、更简单?

【问题讨论】:

    标签: javascript functional-programming


    【解决方案1】:

    您可以通过单次迭代从x 创建一个xObj,而不是在x 上迭代x,而是在y 上的循环中检查它是否存在于xObj (constant lookup O(1) ) 如果是的话然后更新它,否则使用现有值。

    const x = [{id: 1, a: 5}, {id: 2, a:10}, {id: 3, a: 12}];
    
    const y = [{id: 4, a: 0}, {id: 2, a: 0}, {id: 3, a: 0}];
    
    var xObj = {};
    
    x.forEach(function(val){
      xObj[val.id] = val.a;
    });
    
    const newY = y.reduce(function(o,i){
        if(xObj.hasOwnProperty(i.id)){
         i.a = xObj[i.id];
      }
      o.push(i);
      return o;
    },[]);
    
    console.log(newY);
    

    【讨论】:

      【解决方案2】:

      使用Set 存储x 数组中可用的ids 并使用map 覆盖y 数组来检查y's id 是否存在于Set 中。

      const x = [{id: 1, a: 5}, {id: 2, a:10}, {id: 3, a: 12}];
      
      const y = [{id: 4, a: 0}, {id: 2, a: 0}, {id: 3, a: 0}];
      
      const mapped = Object.values(x).reduce((acc, {id}) => {
        acc.add(id)
        return acc;
      }, new Set());
      
      const result = y.map((obj, index) => mapped.has(obj.id) ? {...obj, a: x[index].a} : obj);
      
      console.log(result);

      希望这会有所帮助!

      【讨论】:

        【解决方案3】:

        对于这样的问题,您应该更少关心创建新数组的计算开销,而更多关心遍历多个数组的 Big O 开销多次。您的解决方案和@NitishNarang 发布的另一个解决方案似乎都是 O(n^2),因为随着您的数组变大,求解所需的步骤数呈指数级增长。

        就我个人而言,我会简单地创建一个新的Map() 并逐一检查每个项目,仅当与该 ID 对应的 a 的值大于当前存储的值时,才将其添加到 Map() 中。它基本上是一个稍微复杂的排序练习,除了输入唯一的 ID 值。

        const x = [{id: 1, a: 5}, {id: 2, a:10}, {id: 3, a: 12}];
        const y = [{id: 4, a: 0}, {id: 2, a: 0}, {id: 3, a: 0}];
        const myMap = new Map();
        for (const ea of x) {
          if (!myMap.has(ea.id) || ea.a >= myMap.get(ea.id).a) {
            myMap.set(ea.id, ea);
          }
        }
        for (const ea of y) {
          if (!myMap.has(ea.id) || ea.a >= myMap.get(ea.id).a) {
            myMap.set(ea.id, ea);
          }
        }
        const result = [...myMap.values()];
        

        这个解决方案是 O(n),即它是线性的,这意味着如果您向数组 xy 或两者添加 10 或 100 或 1000 个以上的项目,它只会添加更多的运行步骤解决方案而不是 10^2 或 100^2 或 1000^2,因为您必须检查每个数组中的每个项目与另一个数组中的每个其他项目(就像您对原始解决方案所做的那样。)

        编辑:正如@SZenC 指出的那样,上述解决方案并不完全正确,因为它结合了两个数组。为了仅当它们最初存在于数组y 中时才选择性地匹配项目,只需先迭代y,然后仅在迭代x 时替换值(如果它们已经存在于映射中):

        const x = [{id: 1, a: 5}, {id: 2, a:10}, {id: 3, a: 12}];
        const y = [{id: 4, a: 0}, {id: 2, a: 0}, {id: 3, a: 0}];
        const myMap = new Map();
        for (const ea of y) {
          if (!myMap.has(ea.id) || ea.a >= myMap.get(ea.id).a) {
            myMap.set(ea.id, ea);
          }
        }
        for (const ea of x) {
          if (myMap.has(ea.id) && ea.a >= myMap.get(ea.id).a) {
            myMap.set(ea.id, ea);
          }
        }
        const result = [...myMap.values()];
        

        【讨论】:

        • 这是一个更复杂的解决方案,但我喜欢这个,谢谢
        • 多行代码并不一定意味着“复杂”。好的代码易于遵循且高效,即使这意味着它会占用更多空间。有时,“聪明”的单行解决方案实际上效率极低且难以破译。 :)
        • 确实在计算上更好,但result 值不正确,因为它包含所有 id。 OP 只要求y 中出现的人
        • @SZenC 你是对的。我已更新我的答案以反映原始问题。
        • @jered 感谢您引起我的注意,您的意思是最好避免使用单行解决方案???
        【解决方案4】:

        请试试这个。它使用“map”和“find

        const x = [{id: 1, a: 5}, {id: 2, a:10}, {id: 3, a: 12}];
        
        const y = [{id: 4, a: 0}, {id: 2, a: 0}, {id: 3, a: 0}];
        
        const result = y.map(yData => (xResult = x.find(xData => xData.id == yData.id), xResult && { ...yData, a: xResult.a } || yData))
        
        console.log(result)

        【讨论】:

        • 抱歉,兄弟,但有一个问题,这会将 y 中的对象替换为 x 中的对象!!!,我不需要,我需要相同的项目,只是更改了 a 的值跨度>
        • “简单”,因为它使用单行来求解,但由于它是 O(n^2),因此计算量非常大。你真的不想从另一个数组的Array.map() 内部做一个数组的Array.find()...
        • 编辑解决方案以迎合@SaherElgendy 仅“a”属性更改
        • 正确@jered,但我相信这完全取决于Saher 使用大数据的方式。如果它在数百条记录中,那么我们可能会看到时差,但如果它相对较小,则几乎没有注意到任何时差
        • 但是鉴于您提到的计算差异,您是正确的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-11-18
        • 2017-06-07
        • 1970-01-01
        • 2021-12-19
        • 2011-02-03
        • 2023-01-08
        • 2021-06-10
        相关资源
        最近更新 更多