数组对象合并 我想达到我想要得结果

先看下数据截图

clipboard.png

我想让这两个 数组对象合在一起 如果key 值相同 就保留上面得数据 这数据可能有多条 也有可能有10条数组对象 应该如何去做 完全没思路

阅读 4.1k
5 个回答
// 假设上面是 `a`,下面是 `b`,两个都是对象数组,那么

const a = [];   // 示例用空数组代替,因为你没给示例数据啊
const b = [];   // 示例用空数组代替

// KEY 值相同……那么哪个是 key?假设 arrivedAmount 吧
const key = "arrivedAmount";

// 从其中一个生成映射表,具体用哪个取决于你希望用哪一个作为基数据,
// 那么就把另一个生成映射表,比如我希望用 b 作为基数据
const pairs = a.map(t => [t[key], t]);
const aMap = new Map(pairs);

// 现在来遍历 b,生成对应的数据,这个 r 就是结果
const r = b.map(t => ({...t, ...(aMap.get(t[key]) || {})}));
// 解释 aMap.get(t[key]) || {}:
//   由于 aMap.get(...) 可能取到 undefined,所以用 {} 代替,
//   以避免合并的时候出错
console.log(r);     
// 如果环境不支持显示成员,那就先转化成 JSON 再打印
// console.log(JSON.stringify(r, null, 4));

上面以第二个数组为作基数据来合并的数据,类似 SQL 查询中 from b left join a
如果要把两边的所有数据合并起来,还需要检查哪些数据存在于 a 中而不存在于 b
基于上面的代码,可以在每次 aMap.get() 之后,调用 aMap.delete() 把取过的数据删掉,那遍历完成之后剩下的,补充在 r 之后就行


const pairs = a.map(t => [t[key], t]);
const aMap = new Map(pairs);

这里使用了 ES2015 引入的 Map 对象,要搞明白这个东西,需要先了解 Map:Map - MDN。我比较喜欢看英文原版,但如果你想看中文版,可以在 Language 那里选。

这个类的构造函数是 Map([iterable]),其中 iterable 是一个数组,该数组的每个元素也是数组 —— [key, value] 这样的两个元素的数组。所以 const pairs = ... 这里就是为了生成 iterable 参数。

a 是一个数组,a.map 是调用的 Array.prototype.map。这里的重点是搞明白 .map 的参数,那个 callback 干什么。

对于 [{ a: 1, b: 2, value: 3}, { a: 2, b: 3, value: 4}] 这样一个数组来说,第 1 个 t => [t[key], t] 转换(假设 key === 'a')会得到:[1, { a: 1, value: 3}]

这里要说明一点,后面改为多 KEY 的时候,这里的 key 要换成你想要的值,也就是

const keys = ["a", "b"];
function getKey(model) {
    return keys.map(key => model[key]).join("|");
}
// ...
const pairs = a.map(t => [getKey(t), t]);

你自己模拟一下处理过程,第一个元素,可以看到 getKey 干的事情是,遍历 ["a", "b"],产生一个这样的转换

转换方法:key => model[key],对象 { a: 1, b: 2, value: 3}
所以:

  • "a" => 1
  • "b" => 2

最后 join 得到 "1|2"

那么 pairs 的第 1 个元素就是 ["1|2", { a: 1, b: 2, value: 3}]

最终从 pairs 构造出的 Map 对象是这样一个映射关系

  • "1|2" => { a: 1, b: 2, value: 3}
  • "2|3" => { a: 2, b: 3, value: 4}

从这个映射表对象,只要能生成 key,就能查到原对象(用 aMap.get(...)


// 现在来遍历 b,生成对应的数据,这个 r 就是结果
const r = b.map(t => ({...t, ...(aMap.get(t[key]) || {})}));

这里也是一个 map 转换,从 t 转换成 {...t, ...(aMap.get(t[key]) || {})},这里 {...a, ...b} 用到了 Spread 语法。简单的说,就是把对象展开,所有属性组合起来形成新对象。

转换结果是两个部分组成 ...t...(...),前面很好理解,就是直接把 t 展开;后面部分就是在查表

这里不得不说,t[key] 要改成 getKey(t),因为我们需要得到 "1|2" 这样的东西,在 aMap 中去找相应的对象。

如果找到了,直接展开拼接属性,如果有同名属性,覆盖(Spread 语法)。但是有可能会找不到,那 aMap.get(...) 会返回 undefined。但是 ...undefined 是语法错误,所以需要把 undefined 处理成空对象 {},也就是 ... || {}


总结一下,这里涉及到了这么一些知识

相关知识可以看我的博客:

两个数组的 length 和顺序是一致的嘛?如果一致的话可以使用双重循环,再使用Object.assign合并。

const obj1 = {a:1,b:2,c:3,d:4}
const obj2 = {a:10,c:10,z:100}
const newObj = Object.assign({},obj2,obj1)
// {a: 1, c: 3, z: 100, b: 2, d: 4}

遍历一个附加的数组。然后用key做hash

然后遍历主数组。Object.assign({},item,hash[item.key] || {})

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏