比较两个数组并通过使用javascript保留现有对象来用新值更新 [英] Compare two arrays and update with the new values by keeping the existing objects using javascript
问题描述
下面是我的两个数组。我想比较它们,结果数组应包含更新后的值。Id是常见的。.
数组跨越n个级别,即没有固定级别。 / p>
第一个数组,即更新前的数组。
var parentArray1 = [
{
id:1,
name: test,
context:[
{
id:1.1,
name: test 1.1
}
]
},
{
id:2,
name: test
},
{
id:3,
name: test,
context: [
{
id:3.1,
name: test 3.1
}
]
},
{
id:4,
名称:测试
}
]
我执行的操作是
1.A填充新项目
2.更新现有项目
由于这两个操作,更改后的值将在另一个数组中。 b $ b,即
varchangedArray =
[
{
id:1,1,
name: test1,
context:[
{
id:1.1,
name :更改后的测试1.1
}
]
},
{
id:5,
name: test5
}
]
现在,我编写了一个遍历parentArray1和使用独特的属性我需要添加一个新项目,如果该项目在 changedArray 中,或者在任何级别更新现有项目
结果数组应为..
[
{
id:1,
name: test,
context:[
{
id:1.1,
name:更改的测试1.1
}
]
},
{
id:2,
name: test
},
{
id:3,
name: test,
context:[
{
id:3.1,
name :测试3.1
}
]
},
{
id:4,
name: test
},
{
id:5,
name: test5
}
]
泛型函数:
compareArray(parentArray1, changeArray,[ id]);
函数compareArray(array1,array2,propertyArray){
var newItem = new Array();
array2.map(function(a1Item){
array1.map(function(a2Item){
/ if array loop again /
if(a2Item.constructor === Array) {
compareArray(a2Item,a1Item)
}否则{
/循环属性名称以进行验证/
propertyArray.map(function(property){
if(a2Item [property]){
if(a2Item [property] === a1Item [property]){
a2Item = a1Item
} else {
var isAvailable = _.find(newItem ,function(item){
return item [property] === a1Item [property]
})
if(!isAvailable){
newItem.push(a1Item);
}
}
}
})
}
});
});
/将新项目插入源数组/
newItem.map(function(item){
array1.push(item);
});
console.log( Compare之后: + array1);
}
这就是我的想法
function sameKeys(o1,o2,keys){
for(var i = 0; i< keys.length; i ++){
var key = keys [i];
if(!o1.hasOwnProperty(key)||!o2.hasOwnProperty(key))
抛出比较对象没有键 +键;
if(o1 [key]!== o2 [key])
返回false;
}
返回true;
}
函数isNothing(o){
return typeof(o)===未定义 || o === null;
}
//如果对象具有作为属性的功能
函数clone(o){
if(isNothing(o))
//返回o;
return JSON.parse(JSON.stringify(o));
}
函数extend(o1,o2,键){
if(isNothing(o2))
return;
if(isNothing(o1))
throw(第一个参数不能为空);
if(typeof(o1)!='对象'|| typeof(o2)!='对象')
抛出(扩展仅对对象有效);
Object.keys(o2).forEach(function(key){
var newVal = o2 [key];
if(o1.hasOwnProperty(key)){
if( isNothing(newVal)){
delete o1 [key];
} else
if(Array.isArray(newVal)){
compareArray(o1 [key],newVal,keys );
} else {
switch(typeof(newVal)){
case'object':
extend(o1 [key],newVal,keys);
break;
case'boolean':
case'number':
case'string':
o1 [key] = newVal;
中断;
默认值:
throw'不支持的属性类型:'+ typeof(newVal);
}
}
} else {
o1 [key] = clone(newVal) ;
}
});
}
函数removeFromArray(arr,ids,keyArray){
var index = [];
var it1s = arr.forEach(函数(it,idx){
if(sameKeys(ids,it,keyArray)){
index.push(idx);
}否则{
Object.keys(it).forEach(function(key){
var newVal = it [key];
if(Array.isArray(newVal)){
removeFromArray(it [key],ids,keyArray);
}
});
}
});
if(indexes.length){
if(indexes.length> 1)
throw'找到同一键组合的多个可能对象'
arr.splice(indexes [ 0],1);
}
}
函数compareArray(a1,a2,keyArray){
a2.forEach(function(it2){
var it1s = a1.filter(function(it){
return sameKeys(it2,it,keyArray);
});
var it1;
if(!it1s.length) {
it1 = clone(it2);
a1.push(it1);
}否则{
if(it1s.length> 1)
throw'found同一键组合的多个可能对象'
it1 = it1s [0];
extend(it1,it2,keyArray);
}
if(it2.removedIds){
it2.removedIds.forEach(function(ids){
removeFromArray(a1,ids,keyArray);
});
}
});
}
与 compareArray(parentArray1一起使用,changedArray,['id']);
请注意,它不适用于包含函数的对象。同样,如果数组很大,也许更好的解决方案是按键对两个数组进行排序,然后始终从最后找到的对象开始查找。
使用Nina的一些概念和一些代码清除功能对其进行了更新。
据我了解,您只想添加属性。因此,extend({a:{b:2}},{a:{c:3}})将产生{a:{b:2,c:3}}。如果这不是您想要的,请告诉我。
我还添加了删除ID的功能。如果数组中的任何对象包含格式为 [{id:4},{id:5}] $的
removedIds
数组c $ c>,则具有这些ID的项目将从原始数组中删除。
Below are my two arrays .I want to compare them and the resultant array should contain the updated values.Id's are common.. The arrays spans to n levels ie., there is no fixed levels..
The first array ie., the array before updation..
var parentArray1=[
{
"id": 1,
"name": "test",
"context": [
{
"id": 1.1,
"name": "test 1.1"
}
]
},
{
"id": 2,
"name": "test"
},
{
"id": 3,
"name": "test",
"context": [
{
"id": 3.1,
"name": "test 3.1"
}
]
},
{
"id": 4,
"name": "test"
}
]
The operations that i performed are
1.Adding a new Item 2.Updating an existing item
As a result of these two operations the changed values I will be getting in a different array.. ie.,
var changedArray=
[
{
"id": 1,
"name": "test1",
"context": [
{
"id": 1.1,
"name": "Changed test 1.1"
}
]
},
{
"id": 5,
"name": "test5"
}
]
Now I have written a generic function that loops through the parentArray1 and using the unique propertiesI need to either add a new item,if the item is there in the changedArray or update an existing item at any level
The resultant array should be ..
[
{
"id": 1,
"name": "test",
"context": [
{
"id": 1.1,
"name": "Changed test 1.1"
}
]
},
{
"id": 2,
"name": "test"
},
{
"id": 3,
"name": "test",
"context": [
{
"id": 3.1,
"name": "test 3.1"
}
]
},
{
"id": 4,
"name": "test"
},
{
"id": 5,
"name": "test5"
}
]
Generic function:
compareArray(parentArray1, changedArray, ["id"]);
function compareArray(array1, array2, propertyArray) {
var newItem = new Array();
array2.map(function(a1Item) {
array1.map(function(a2Item) {
/ If array loop again /
if (a2Item.constructor === Array) {
compareArray(a2Item, a1Item)
} else {
/ loop the property name to validate /
propertyArray.map(function(property) {
if (a2Item[property]) {
if (a2Item[property] === a1Item[property]) {
a2Item = a1Item
} else {
var isAvailable = _.find(newItem, function(item) {
return item[property] === a1Item[property]
})
if (!isAvailable) {
newItem.push(a1Item);
}
}
}
})
}
});
});
/ Insert the new item into the source array /
newItem.map(function(item) {
array1.push(item);
});
console.log("After Compare : " + array1);
}
This is what I came up with:
function sameKeys(o1, o2, keys) {
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (!o1.hasOwnProperty(key) || !o2.hasOwnProperty(key))
throw 'compared objects do not have the key ' + key;
if (o1[key] !== o2[key])
return false;
}
return true;
}
function isNothing(o) {
return typeof(o) === 'undefined' || o === null;
}
// this does not work if objects have functions as properties
function clone(o) {
if (isNothing(o))
return o;
return JSON.parse(JSON.stringify(o));
}
function extend(o1, o2, keys) {
if (isNothing(o2))
return;
if (isNothing(o1))
throw ('first parameter cannot be empty');
if (typeof(o1) != 'object' || typeof(o2) != 'object')
throw ('extend only works on objects');
Object.keys(o2).forEach(function (key) {
var newVal = o2[key];
if (o1.hasOwnProperty(key)) {
if (isNothing(newVal)) {
delete o1[key];
} else
if (Array.isArray(newVal)) {
compareArray(o1[key], newVal, keys);
} else {
switch (typeof(newVal)) {
case 'object':
extend(o1[key], newVal, keys);
break;
case 'boolean':
case 'number':
case 'string':
o1[key] = newVal;
break;
default:
throw 'not supported property type: ' + typeof(newVal);
}
}
} else {
o1[key] = clone(newVal);
}
});
}
function removeFromArray(arr, ids, keyArray) {
var indexes = [];
var it1s = arr.forEach(function (it, idx) {
if (sameKeys(ids, it, keyArray)) {
indexes.push(idx);
} else {
Object.keys(it).forEach(function (key) {
var newVal = it[key];
if (Array.isArray(newVal)) {
removeFromArray(it[key], ids, keyArray);
}
});
}
});
if (indexes.length) {
if (indexes.length > 1)
throw 'found multiple possible objects for the same key combination'
arr.splice(indexes[0], 1);
}
}
function compareArray(a1, a2, keyArray) {
a2.forEach(function (it2) {
var it1s = a1.filter(function (it) {
return sameKeys(it2, it, keyArray);
});
var it1;
if (!it1s.length) {
it1 = clone(it2);
a1.push(it1);
} else {
if (it1s.length > 1)
throw 'found multiple possible objects for the same key combination'
it1 = it1s[0];
extend(it1, it2, keyArray);
}
if (it2.removedIds) {
it2.removedIds.forEach(function (ids) {
removeFromArray(a1, ids, keyArray);
});
}
});
}
Use it with compareArray(parentArray1,changedArray,['id']);
Note that it would not work with objects that contain functions. Also, if the arrays would be large, perhaps a better solution is to sort both arrays by key, then always look from the last found object up. That's all I got for now.
Updated it with some concepts from Nina and some clearing of the code.
As I understood it, you only want to add properties. So extend({a: {b: 2}},{a:{c:3}}) will result in {a: {b:2,c:3}}. If this is not what you wanted, let me know.
I also added functionality for removing ids. If any of the objects in the array contains a removedIds
array of the form [{id: 4},{id: 5}]
then the items with those ids will be removed from the original array.
这篇关于比较两个数组并通过使用javascript保留现有对象来用新值更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!