我如何合并包含对象的JavaScript数组,重复数据删除并保留新对象

How can I merge JavaScript arrays containing objects, deduplicate and keep the newer object

本文关键字:对象 数据 删除 新对象 保留 JavaScript 何合并 合并 包含 数组      更新时间:2023-09-26

我试图通过检查标题是否相同来合并两个对象数组,如果是,则检查哪个条目较新,并丢弃较旧的。我已经找到了很多解决方案来丢弃真正的重复,但是我如何才能做到这一点,我可以根据日期决定保留哪些?

const a = [{
  "title": "title1",
  "date": "2010-08-20T15:51:58"
}, {
  "title": "title2",
  "date": "2015-09-20T16:45:21"
}]
const b = [{
  "title": "title1",
  "date": "2015-08-20T15:51:58"
}, {
  "title": "title2",
  "date": "2015-09-20T16:45:21"
}]

谢谢你提供的任何提示!

下面是ES6代码:

var res = Array.from([...a,...b].reduce ( (hash, v) =>
    !hash.has(v.title) || hash.get(v.title).date < v.date ? hash.set(v.title, v) : hash
, new Map()), v => v[1]);

var a = [{
"title": "title1",
"date": "2010-08-20T15:51:58"
}, {
"title": "title2",
"date": "2015-09-20T16:45:21"
}]
var b = [{
"title": "title1",
"date": "2015-08-20T15:51:58"
}, {
"title": "title2",
"date": "2015-09-20T16:45:21"
}]
var res = Array.from([...a,...b].reduce ( (hash, v) =>
    !hash.has(v.title) || hash.get(v.title).date < v.date ? hash.set(v.title, v) : hash
, new Map()), v => v[1]);
console.log(res);

解释

首先,使用展开操作符将输入数组连接成一个新数组:

[...a,...b]

然后创建一个空的Map并将其作为最后一个参数传递给reduce:

new Map()

reduce方法为连接数组中的每个元素调用箭头函数。箭头函数也接受上述映射作为参数(如hash)。

箭头函数必须返回一个值。然后将该值再次传递给该函数的后续调用(对于下一个元素),因此我们总是返回映射,映射在每次函数调用中都会增长。可以说,它是从一个调用传递到下一个调用。在最后一次调用中,返回的map成为.reduce()的返回值。

箭头函数本身检查当前元素的标题是否不在映射中:

!hash.has(v.title)

如果它已经在映射中,则还计算下一个表达式;它检查map条目中的日期是否在当前元素的日期之前。

hash.get(v.title).date < date

如果以上任何一个条件为真(不在map中,或者具有较小的日期),则以当前元素作为值(重新)创建map条目。

? hash.set(v.title, v)

set也返回设置后的整个地图。否则映射将原封不动地返回:

: hash

因此reduce()的结果是一个映射,以标题为关键字。这确实是您需要的结果,但它是Map格式的。要将其恢复为普通数组,需要对其调用Array.from方法。这将Map值更改为一个键值对数组(包含2个元素的子数组)。因为我们只对值感兴趣,所以我们对它应用一个函数:

v => v[1]

只用第二个值替换每一对。这个函数作为第二个参数传递给Array.from,它将它应用于每一对。

一些评论

  • 这假设你的日期是ISO格式的,就像在你的示例中一样:在这种情况下,字符串比较给出正确的结果来确定一个日期是否先于另一个日期。

  • 结果还将包括只在两个输入数组中的一个中出现的对象

  • 这很容易扩展到三个输入数组:只需添加第三个输入数组:[...a,...b,...c]

  • 这在O(n)时间内运行,其中n是输入数组中存在的对象总数。这是因为大多数JavaScript引擎实现Map访问操作,如.has, .get.putO(1)时间

a.forEach(function(elem1,count1){
   b.forEach(function(elem2,count2){
   //loop trough each a frouvh each b
     if(elem1.title==elem2.title){
       var date1=new Date(elem1.date);
       var date2=new Date(elem2.date);
       if(date1.getTime()>date2.getTime()){
            //elem from a is older
            //delete elem from a
         }else{
            //elem from b is older
         }
       }
    });
   });
var a = [{
  "title": "title1",
  "date": "2010-08-20T15:51:58"
}, {
  "title": "title2",
  "date": "2015-09-20T16:45:21"
}]
var b = [{
  "title": "title1",
  "date": "2015-08-20T15:51:58"
}, {
  "title": "title2",
  "date": "2015-09-20T16:45:21"
}]
function assign(a, b) {
  return a.reduce((acc, itemA) => {
    const {title: titleA, date: dateA} = itemA
    const itemB = b.find(({title: titleB}) => titleA == titleB) 
    if (itemB) {
      if (new Date(dateA) - new Date(itemB.date) >= 0) {
        acc.push(itemA)
      } else {
        acc.push(itemB)
      }
    }
    return acc
  }, [])
}

可以使用for loop, new Date().getTime()

var a = [{
"title": "title1",
"date": "2010-08-20T15:51:59"
}, {
"title": "title2",
"date": "2015-09-20T16:45:22"
}];
var b = [{
"title": "title1",
"date": "2015-08-20T15:51:58"
}, {
"title": "title2",
"date": "2015-09-20T16:45:21"
}];
var res = [];
for (var i = 0; i < a.length; i++) {
  var curr = a[i];
  for (var n = 0; n < b.length; n++) {
    if (curr.title === b[n].title) {
      if (new Date(curr.date).getTime() > new Date(b[n].date).getTime()) {
        res.push(curr)
      } else {
        res.push(b[n])
      }
    }
  }
}
console.log(res);