我如何合并包含对象的JavaScript数组,重复数据删除并保留新对象
How can I merge JavaScript arrays containing objects, deduplicate and keep the newer object
我试图通过检查标题是否相同来合并两个对象数组,如果是,则检查哪个条目较新,并丢弃较旧的。我已经找到了很多解决方案来丢弃真正的重复,但是我如何才能做到这一点,我可以根据日期决定保留哪些?
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
和.put
的O(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);
- 将嵌套对象数据添加到窗体中
- 使用javascript更改嵌套对象数据
- 如何将状态对象/数据传递给(异步)ajax 回调
- 如何使用HTML5中的sessionStorage概念在Javascript中打印对象数据
- 如何在express中使用socket.io发布多个对象数据
- 如何在 Javascript 中将函数绑定到对象数据成员的更改
- 在$.ajax调用中将附加数据添加到jQuery包装的对象数据中
- 当点击处理程序添加到谷歌地图圆圈标记时,无法访问对象数据
- JavaScript对象数据和数组
- 访问主数组内的数组中的对象数据
- 角度.js从NG重复更新对象数据
- HTML 对象数据文件(如果未找到)
- 设置对象数据结构数组属性
- Ajax 请求不发送我的对象数据
- 获取对象数据的浅拷贝的最快方法是什么
- 如何访问对象的键值?希望从对象数据填充表
- JSON.parse 似乎不解析对象数据
- 在 android WebView 中的 java 和 javascript 之间共享对象(数据)
- 选择 JSON 对象数据表元素以列出其所有元素
- 当响应 JSON 对象数据计数为零时,AJAX 成功回调函数重定向到错误回调