【问题标题】:Using JavaScript reduce to update and add to array of objects使用 JavaScript reduce 更新并添加到对象数组
【发布时间】:2021-10-10 10:23:56
【问题描述】:

我正在尝试解决 JavaScript 中的一个问题,并且相信使用 reduce 方法会是最优雅的。我有一组看起来像这样的对象:

let existingLots = [
    {
        id: 1,
        title: 'one',
        colour: 'red',
        speed: 100
    },
    {
        id: 2,
        title: 'two',
        colour: 'blue',
        speed: 70
    },
    {
        id: 3,
        title: 'three',
        colour: 'white',
        speed: 120
    },
    {
        id: 4,
        title: 'four',
        colour: 'yellow',
        speed: 90
    },
]

还有一个看起来像这样的数组:

let newLots = [
    {
        id: 1,
        title: 'one',
        colour: 'orange',
        speed: 100,
        owner: 'Ted'
    },
    {
        id: 2,
        title: 'two',
        colour: 'blue',
        speed: 75
    },
    {
        id: 3,
        title: 'three updated',
        colour: 'white',
        speed: 120,
    },
    {
        id: 4,
        title: 'four',
        colour: 'yellow',
        speed: 90
    },
    {
        id: 5,
        title: 'five',
        colour: 'green',
        speed: 50
    },
]

如您所见,一些 id 之间存在重叠。我想更新existingLots 数组,以便如果一个对象与newLots 数组中的一个共享相同的id,则该对象将使用其newLots 对应项中的任何新属性/值进行更新。另外,我希望将不在existingObjects 中的newLots 中的任何对象(即具有id5 的对象)添加到existingObjects 数组中。

我尝试了以下方法,但没有达到预期的结果:

const res = existingLots.reduce((acc, obj) => {
    let updatedObj = newLots.filter(newLot => newLot.id === obj.id);
    // if object exists in currentLots, merge it
    if(updatedObj) {
        [...acc, {...obj, ...updatedObj}]
    } else {
        let newObj = !newLots.filter(newLot => newLot.id === obj.id);
        [...acc, {...newObj}]
    }
    return acc
}, [])

我是 JavaScript 数组方法的新手,因此不胜感激。

【问题讨论】:

    标签: javascript arrays object reduce


    【解决方案1】:

    1)您正在使用filter,它将返回一个过滤器元素数组

    filter() 方法创建一个包含所有通过的元素的新数组 由提供的函数实现的测试。 -MDN

    2)此代码只是在数组中的最后一个元素之后推送/添加所有对象,然后丢弃,因为您没有将它们存储在任何地方

    [...acc, {...obj, ...updatedObj}]
    

    解决方案:您可以使用forEach 循环遍历newLots 数组并将数据添加到existingLots 元素

    newLots.forEach((newLot) => {
      let objExist = existingLots.find((o) => o.id === newLot.id);
      if (objExist) {
        for (let key in newLot) objExist[key] = newLot[key];
      } else existingLots.push(newLot);
    });
    

    newLots.forEach((newLot) => {
      let index = existingLots.findIndex((o) => o.id === newLot.id);
      if (index !== -1) existingLots[index] = { ...existingLots[index], ...newLot };
      else existingLots.push(newLot);
    });
    

    let existingLots = [
      {
        id: 1,
        title: "one",
        colour: "red",
        speed: 100,
      },
      {
        id: 2,
        title: "two",
        colour: "blue",
        speed: 70,
      },
      {
        id: 3,
        title: "three",
        colour: "white",
        speed: 120,
      },
      {
        id: 4,
        title: "four",
        colour: "yellow",
        speed: 90,
      },
    ];
    
    let newLots = [
      {
        id: 1,
        title: "one",
        colour: "orange",
        speed: 100,
        owner: "Ted",
      },
      {
        id: 2,
        title: "two",
        colour: "blue",
        speed: 75,
      },
      {
        id: 3,
        title: "three updated",
        colour: "white",
        speed: 120,
      },
      {
        id: 4,
        title: "four",
        colour: "yellow",
        speed: 90,
      },
      {
        id: 5,
        title: "five",
        colour: "green",
        speed: 50,
      },
    ];
    
    newLots.forEach((newLot) => {
      let index = existingLots.findIndex((o) => o.id === newLot.id);
      if (index !== -1) existingLots[index] = { ...existingLots[index], ...newLot };
      else existingLots.push(newLot);
    });
    
    console.log(existingLots);

    【讨论】:

    • 完美运行,我学到了很多,谢谢!
    【解决方案2】:

    我认为你可以使用一些“魔法”的唯一地方是查找。这段代码在对象 id-s 和它们在实际数组中的索引之间创建一个map,然后循环遍历更新器数组,使用map 查找和更新现有对象,如果它是id,则简单地附加对象是全新的。

    let existingLots = [{
        id: 1,
        title: 'one',
        colour: 'red',
        speed: 100
      },
      {
        id: 2,
        title: 'two',
        colour: 'blue',
        speed: 70
      },
      {
        id: 3,
        title: 'three',
        colour: 'white',
        speed: 120
      },
      {
        id: 4,
        title: 'four',
        colour: 'yellow',
        speed: 90
      },
    ];
    
    let newLots = [{
        id: 1,
        title: 'one',
        colour: 'orange',
        speed: 100,
        owner: 'Ted'
      },
      {
        id: 2,
        title: 'two',
        colour: 'blue',
        speed: 75
      },
      {
        id: 3,
        title: 'three updated',
        colour: 'white',
        speed: 120,
      },
      {
        id: 4,
        title: 'four',
        colour: 'yellow',
        speed: 90
      },
      {
        id: 5,
        title: 'five',
        colour: 'green',
        speed: 50
      },
    ];
    
    let map = existingLots.reduce((acc, obj, idx) => acc.set(obj.id, idx), new Map());
    for (let obj of newLots)
      if (map.has(obj.id)) {
        let idx = map.get(obj.id);
        existingLots[idx] = {...existingLots[idx], ...obj};
      } else
        existingLots.push(obj);
    
    
    console.log(existingLots);

    更新程序部分实际上也可以在您的代码中工作,就像 filter() 总是为您提供一个数组一样,if(updatedObj) 应该是 if(updatedObj.length) 并且 updatedObj 的用法将是 updatedObj[0]acc =(或简单的return)也不见了。 但是所有这些数组方法(filter()reduce()map())通常都在单个数组上工作,它们并不适合根据条件从另一个数组中追加元素,所以第二个 if 可以不起作用 - 为此,您最好使用两个答案所建议的简单循环,然后更新可能发生在同一个循环中。

    【讨论】:

      猜你喜欢
      • 2018-05-28
      • 1970-01-01
      • 2018-12-07
      • 1970-01-01
      • 1970-01-01
      • 2019-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多