[英]How to detect object differences between two arrays?
我正在嘗試比較兩個對象數組,並返回更新對象的列表。 我不想只使用lodash
的javascript數據結構和函數。
例如:
I have a first array which named arr1 = [
{
name: 'attribute 1',
id: 12,
value: 40,
docs:[],
version: 1,
},
{
name: 'attribute 41',
id: 12,
value: 6,
version: 1,
}
]
還有另一個數組:
array2 = [
{
name: 'attribute 1',
attributeTypeId: 12,
value: 65,
docs: ['bla bla']
}
]
我正在嘗試遍歷兩個數組並檢測差異並返回這樣的數組:
result = [
{
name: 'attribute 1',
id: 12,
value: 65,
docs:['bla bla'],
version: 1,
},
{
name: 'attribute 41',
id: 12,
value: 6,
version: 1,
}]
我寫了一些不完整的功能(尚未優化但只是蠻力的解決方案):
const filterProperties = (e) => {
return e.toLowerCase() !== 'name' && e.toLowerCase() !== 'id'
}
// function sort
const sortProperties = (a, b) => a < b ? -1 : 1;
let result = []
attributesUpdate.forEach(attr => {
const attrProps = Object.getOwnPropertyNames(attr);
// iterate the attributes
for (let i = 0; i < attributes.length; i++) {
let attribute = attributes[i];
// check if the attribute to update has a different name or attributeTypeId
if (attribute.name !== attr.name) {
result = result.concat(attr);
}
// check if the attribute to update has the same name, id
// of the originalOne
if (attribute.name === attr.name && attribute.id=== attr.id) {
let obj = {
name: attribute.name,
id: attribute.id,
}
// get the properties of the attribute
const attributeProps = Object.getOwnPropertyNames(attribute);
// extract the name and id from the list
const filtredAttributeProps = attributeProps.filter(filterProperties);
const filteredattrProps = attrProps.filter(filterProperties);
// returns the length of each array of properties
const attrLength = filteredattrProps.length;
const attributeLength = filtredAttributeProps.length;
if (attrLength === attributeLength) {
for (let j = 0; j < attrLength; j++) {
const propName = filteredattrProps[j];
obj[propName] = attr[propName];
}
result = result.filter(e => e.name === attr.name
&& e.id=== attr.id)
.map(e => Object.assign(e, {obj}))
}
if (attrLength !== attributeLength) {
// sort the array of properties
const sortedAttrProps = filteredattrProps.sort(sortProperties);
const sortedAttributeProps = filtredAttributeProps.sort(sortProperties);
// check the shortest object
const min = attrLength < attributeLength ? attrLength : attributeLength;
// get the biggest object
const longestObjProps = attrLength === min ? sortedAttributeProps : sortedAttrProps;
const longestObj = attrLength === min ? attribute : attr
const shortestProps = attrLength === min ? sortedAttrProps: sortedAttributeProps;
const shortestObj = attrLength === min ? attr : attribute
// fill the object with attr properties
for(let j = 0; j < min; j++) {
const propName = shortestProps[j];
obj[propName] = shortestObj[propName];
}
// fill the remaining properties in the object
const remainingProperties = longestObjProps.filter(e => !shortestProps.includes(e));
for (let j = 0; j < remainingProperties.length; j++) {
const propName = remainingProperties[j];
obj[propName] = longestObj[propName]
}
if (!result.length || result.filter(e => e.name !== attr.name &&
e.id!== attr.id).length === 0) {
result.concat(obj);
}
}
}
}
})
console.log('result: ', result);
我得到了這樣的結果:
[
{
name: 'attribute 1',
attributeTypeId: 12,
value: 65,
docs: ['bla bla']
}
]
如何修復此代碼以獲得所需的結果? 我希望我的問題不會被否決。 任何建議都將受到歡迎。
該代碼的作用是循環遍歷array2
的對象,然后在發現arr1
中存在匹配的名稱/標識時,它僅更新該對象的屬性。 如果找不到,它將對象添加到arr1
。
arr1 = [{ name: 'attribute 1', id: 12, value: 40, docs: [], version: 1, }, { name: 'attribute 41', id: 12, value: 6, version: 1, } ]; array2 = [{ name: 'attribute 1', attributeTypeId: 12, value: 65, docs: ['bla bla'] }]; updateArray(arr1, array2); console.log(arr1); function updateArray(arrayToUpdate, dataToUpdateWith) { dataToUpdateWith.forEach(function(obj) { var objToUpdate = checkIfNameIdExists(arrayToUpdate, obj.name, obj.attributeTypeId); if (objToUpdate === false) { objToUpdate = obj; arrayToUpdate.push(objToUpdate); } else { for (var prop in obj) { if (objToUpdate.hasOwnProperty(prop)) { var nameInFinalObject = prop; if (prop === "attributeTypeId") { nameInFinalObject = "id"; } objToUpdate[nameInFinalObject] = obj[prop]; } } } }); } function checkIfNameIdExists(arrOfObj, name, id) { if (name === null) { return false; } var output = false; arrOfObj.forEach(function(obj) { if (obj.name === name) { output = obj; return true; } }); return output; }
假設:
每個對象中的值都是相同的類型,並且值沒有嵌套,因此需要遞歸遍歷樹以比較相等性等。
第一個數組是源,后一個數組(具有相同的名稱 )是變異形式。 我們不處理從源對象中刪除屬性的問題。 根據OP給出的內容,我們僅考慮價值變化。
const d1 = [{ name: 'attribute 1', id: 12, value: 40, docs: [], version: 1, }, { name: 'attribute 41', id: 12, value: 6, version: 1, } ] const d2 = [{ name: 'attribute 1', attributeTypeId: 12, value: 65, docs: ['bla bla'] }] const isChanged = (a, b) => Array.isArray(a) ? !a.every(x => b.includes(x)) : a !== b const compare = (o1, o2) => Object.entries(o1).reduce((r, [k,v]) => { if(k in o2 && isChanged(o2[k], v)) Object.assign(r, {[k]: o2[k]}) return r }, o1) const group = (a, b) => [...a, ...b].reduce((r,c) => (r[c.name] = [...r[c.name] || [], c], r), {}) const result = Object.values(group(d1,d2)).reduce((r,c) => (r.push(c.length == 2 ? compare(...c) : c[0]), r), []) console.log(result)
想法是將對象合並到一個數組中,按名稱對它們進行分組,如果有任何更改,則compare
功能將對length of 2
的groups
進行compare
。 否則只是添加到最終結果中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.