【问题标题】:Manipulating object arrays for unique data为唯一数据操作对象数组
【发布时间】:2017-10-17 20:18:44
【问题描述】:

我正在做一个项目,我有 2 个对象数组,以下是数据可能存在的各种情况。

// Case 1
var arr1=[{id:1,quantity:10}]
var arr2=[{id:1,quantity:10},{id:2,quantity:20}]

// Case 2
var arr1=[]
var arr2=[{id:1,quantity:10},{id:2,quantity:20}]

// Case 3
var arr1=[{id:1,quantity:12}]
var arr2=[{id:1,quantity:10},{id:2,quantity:20}]

// Case 4
var arr1=[{id:1,quantity:10},{id:1,quantity:20}]
var arr2=[{id:1,quantity:10}]

因此,array1 可能是空的,可能有来自 array2 的对象之一或具有不同数量值的 array2 的两个对象。

我想根据 arr2 更新主数组或 arr1,但不想用 arr1=arr2 类型的解决方案完全刷 arr1 和 arr2。 arr1 应该根据 arr2 更新数量,并根据同一事物添加或删除。

【问题讨论】:

  • 你能举一个之前/之后的例子吗?
  • 代码如何同时更新和添加和删除元素?
  • 您能解释一下结果与arr1 = arr2 有何不同吗?
  • @trincot 因为我不希望数据来自的 api 替换存储在数组中的所有内容,导致使用数组的视图进入空状态然后再次填充,如果我有上述解决方案会更好
  • 我不确定我是否理解:如果数组内容的替换是同步发生的,那么没有时刻视图会看到数组为空。但是,我确实理解为变量分配一个新数组不会影响对前一个数组的现有引用。为了解决这个问题,您需要 mutate 数组(如我的回答中所建议的那样)。

标签: javascript arrays object


【解决方案1】:

如果arr1 = arr2 是一个解决方案,除了你想改变 arr1 而不是替换它,然后考虑使用splice

var arr1=[{id:0,quantity:1},{id:2,quantity:12},{id:3,quantity:9}],
    arr2=[{id:1,quantity:10},{id:2,quantity:20}];

arr1.splice(0, arr1.length, ...arr2);

console.log(arr1);

如果您担心当id 存在于arr2 中时,arr1 中的对象不应替换,而是变异(保留它们的引用),那么我建议:

var arr1=[{id:0,quantity:1},{id:2,quantity:12},{id:3,quantity:9}],
    arr2=[{id:1,quantity:10},{id:2,quantity:20}];
// key both arrays by id in Maps
var mp1 = new Map(arr1.map(obj => [obj.id, obj])),
    mp2 = new Map(arr2.map(obj => [obj.id, obj]));
// traverse arr1 from right to left so deletions will not affect the loop
arr1.reduceRight( (_, obj, i) => {
    if (mp2.has(obj.id)) {
        Object.assign(obj, mp2.get(obj.id)); // update
    } else {
        arr1.splice(i, 1); // delete
    }
}, null);
arr2.forEach( (obj) => {
    if (!mp1.has(obj.id)) {
        arr1.push(obj); // insert
        // If you need the inserted object to be a copy, then do:
        // arr1.push(Object.assign({}, obj));
    }
});

// If you need the result to be sorted by `id`, then do this also:
arr1.sort( (a,b) => a.id - b.id );

console.log(arr1);

【讨论】:

  • 我尝试了这种方法,但是因为这会将所有内容从 array2 添加到 array1 并且因为我在 angular 中使用这个逻辑来进行 angular-animate 并且这会对所有添加进行动画处理,而不仅仅是一个添加。我只希望添加一个具有动画效果而不是所有内容,因此在这里提出了这个问题,否则一个简单的谷歌搜索就可以解决它。不过谢谢
  • 我添加了第二个解决方案,当 id 存在于 arr2 中时,它会保留 arr1 中的对象引用。
  • 这看起来是正确的,可能会起作用,我回家后会测试它。
  • 这可行,但如果 arr1 有 2 个对象而 arr2 只有 1 个,那么 arr1 仍会产生 2 个对象,而不是从 arr2 更新的 1 个。
  • 糟糕,我现在通过将 forEach 替换为 reduceRight 来解决此问题。
【解决方案2】:
for(const el of arr2){
 const dupe = arr1.find(e => e.id === el.id);
 if(dupe){
   dupe.quantity = el.quantity;
 }else{
   arr1.push(el);
 }
}

但实际上地图(id -> 数量)将是更好的数据结构(或对象):

const els = new Map( arr1.map(el => [el.id, el.quantity]));
//to add
arr2.forEach( el => els.set( el.id, el.quantity + (els.get( el.id ) ||0));

【讨论】:

  • 在第二个解决方案中 - 添加一个默认的 (els.get( el.id ) || 0) 或者如果它不是重复的,你会得到一个 NaN
  • 不错的解决方案,但如果 arr2 的元素比 arr1 少,则 arr1 不会更改为 arr2。
  • @ori 是的,我总是忘记这一点...:/
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-28
  • 1970-01-01
  • 2018-08-10
  • 2022-11-17
  • 2015-05-13
  • 2019-07-15
  • 2021-11-03
相关资源
最近更新 更多