包含对象的两个 js 数组的完全外部连接 - 连接的数组包含新的 属性 'action' (add/remove/edit/same)
Full outer join of two js arrays containing objects - joined array contains new property 'action' (add/remove/edit/same)
我有两个数组 originalArray
和 modifiedArray
,它们的对象具有某些属性; sys_id
是独一无二的 属性:
originalArray = [
{ sys_id: 1234, type: 'XYZZ' },
{ sys_id: 1235, type: 'ABCD' },
{ sys_id: 1236, type: 'IJKL' },
{ sys_id: 1237, type: 'WXYZ' },
{ sys_id: 1238, type: 'LMNO' }
]
modifiedArray = [
{ sys_id: 1234, type: 'XYZZ' },
{ sys_id: 1235, type: 'ZZAA' },
{ sys_id: 1236, type: 'ZZZZ' },
{ sys_id: 1252, type: 'AAAA' }
]
我正在寻找 combine/merge 数组,但包括一个新的 属性,它描述了使用 sys_id 基于原始数组的新数组中更改内容的完整说明属性.
resultingArray = [
{ sys_id: 1234, type: 'XYZZ', action: 'same' },
{ sys_id: 1235, type: 'ZZAA', action: 'edit' },
{ sys_id: 1236, type: 'ZZZZ', action: 'edit' },
{ sys_id: 1237, type: 'WXYZ', action: 'remove' },
{ sys_id: 1238, type: 'LMNO', action: 'remove' },
{ sys_id: 1252, type: 'AAAA', action: 'add' }
还想知道是否有更合适的术语,或者更简洁的方式来解释我在这里试图完成的事情?
我在一个仅限于 ES5 的平台上。
遍历第一个数组,在第二个数组中找到相应的值并基于该生成元素。最后,将剩余的元素添加为新添加的。
var originalArray = [{ sys_id: 1234, type: 'XYZZ' }, { sys_id: 1235, type: 'ABCD' }, { sys_id: 1236, type: 'IJKL' }, { sys_id: 1237, type: 'WXYZ' }, { sys_id: 1238, type: 'LMNO' } ],
modifiedArray = [{ sys_id: 1234, type: 'XYZZ' }, { sys_id: 1235, type: 'ZZAA' }, { sys_id: 1236, type: 'ZZZZ' }, { sys_id: 1252, type: 'AAAA' } ];
// keep a swallow copy to not effect the original one
let mA = modifiedArray.slice();
// iterate over to generate new array
let res = originalArray.map(o => {
// get index of eleemnt
let moi = mA.findIndex(o1 => o1.sys_id === o.sys_id);
// if found
if (moi > -1) {
// remove it from the swallow copied array
let mo = mA.splice(moi,1)[0];
// check and generate new array
return { ...mo, action: mo.type === o.type ? 'same' : 'edited' }
} else {
// if not found return as removed
return { ...o, action: 'removed' }
}
// add remaining values as added
}).concat(mA.map(o=>({...o, action: 'added'})))
console.log(res);
ES5 替代方案:
var originalArray = [{ sys_id: 1234, type: 'XYZZ' }, { sys_id: 1235, type: 'ABCD' }, { sys_id: 1236, type: 'IJKL' }, { sys_id: 1237, type: 'WXYZ' }, { sys_id: 1238, type: 'LMNO' } ],
modifiedArray = [{ sys_id: 1234, type: 'XYZZ' }, { sys_id: 1235, type: 'ZZAA' }, { sys_id: 1236, type: 'ZZZZ' }, { sys_id: 1252, type: 'AAAA' } ];
// function for copying properties to function
function copyProperty(from, to) {
for (var prop in from) {
if (from.hasOwnProperty(prop))
to[prop] = from[prop];
}
return to;
}
var mA = modifiedArray.slice();
var res = originalArray.map(function(o) {
var moi = -1;
// get index by iterating
for (var i = 0; i < mA.length; i++) {
if (mA[i].sys_id === o.sys_id) {
moi = i;
break;
}
}
if (moi != -1) {
var mo = mA.splice(moi, 1)[0];
return copyProperty(mo, { action: mo.type === o.type ? 'same' : 'edited' })
} else {
return copyProperty(o, { action: 'removed' })
}
})
// push remaining values
mA.forEach(function(o) {
res.push(copyProperty(o, { action: 'added' }))
})
console.log(res);
使用 Array#reduce()
生成使用 sys_id
作为键并具有属性 orig
和 mod
的对象,然后使用一个很好的旧 for in
循环来迭代它对象并在 2 种类型存在时进行比较,或者检查哪些类型不存在并将适当的数据推送到结果数组。
所有 ES5 兼容
var grouped = [originalArray, modifiedArray].reduce(function(acc, arr, i) {
var label = i === 0 ? 'orig' : 'mod';
for (var j = 0; j < arr.length; j++) {
var curr = arr[j], id = curr.sys_id;
acc[id] = acc[id] || {orig: null, mod: null };
acc[id][label] = curr;
}
return acc;
}, {});
var res = [];
function insertObj(o, act) {
var newObj = { action: act };
// iterate existing keys to add to new object
for (var k in o) {
if (o.hasOwnProperty(k)) {
newObj[k] = o[k]
}
}
res.push(newObj)
}
for (var key in grouped) {
var action, obj;
if (grouped.hasOwnProperty(key)) {
obj = grouped[key]
if (!obj.orig) {
insertObj(obj.mod, 'add');
} else if (!obj.mod) {
insertObj(obj.orig, 'remove')
} else {
action = obj.mod.type === obj.orig.type ? 'same' : 'edit';
insertObj(obj.mod, action)
}
}
}
console.log(res)
<script>
var originalArray = [
{ sys_id: 1234, type: 'XYZZ' },
{ sys_id: 1235, type: 'ABCD' },
{ sys_id: 1236, type: 'IJKL' },
{ sys_id: 1237, type: 'WXYZ' },
{ sys_id: 1238, type: 'LMNO' }
]
var modifiedArray = [
{ sys_id: 1234, type: 'XYZZ' },
{ sys_id: 1235, type: 'ZZAA' },
{ sys_id: 1236, type: 'ZZZZ' },
{ sys_id: 1252, type: 'AAAA' }
]
</script>
只不过是老式的蛮力做事方式。此外,确保原始输入没有突变也很重要。基本上,我遍历所有内容两次,并检查以下条件:
1) 相同 sys_id 和类型(操作:相同)
2) 相同 sys_id,不同类型(操作:编辑)
3) 不同 sys_id,不同类型(操作:删除)
4) 不同 sys_id,不同类型,对象存在于 modifiedArray 但不存在于 originalArray(操作:添加)
(在没有任何 ES6 的情况下写这个让我很痛苦)
var originalArray = [
{ sys_id: 1234, type: 'XYZZ' },
{ sys_id: 1235, type: 'ABCD' },
{ sys_id: 1236, type: 'IJKL' },
{ sys_id: 1237, type: 'WXYZ' },
{ sys_id: 1238, type: 'LMNO' }
];
var modifiedArray = [
{ sys_id: 1234, type: 'XYZZ' },
{ sys_id: 1235, type: 'ZZAA' },
{ sys_id: 1236, type: 'ZZZZ' },
{ sys_id: 1252, type: 'AAAA' }
];
var resultingArray = [];
for (var i = 0; i < originalArray.length; i++) {
for (var j = 0; j < modifiedArray.length; j++) {
if (originalArray[i].sys_id === modifiedArray[j].sys_id && originalArray[i].type === modifiedArray[j].type) {
resultingArray.push({
sys_id: originalArray[i].sys_id,
type: originalArray[i].type,
action: 'same'
});
break;
} else if (originalArray[i].sys_id === modifiedArray[j].sys_id && originalArray[i].type !== modifiedArray[j].type) {
resultingArray.push({
sys_id: originalArray[i].sys_id,
type: modifiedArray[j].type,
action: 'edit'
});
break;
} else if (originalArray[i].sys_id !== modifiedArray[j].sys_id && originalArray[i].type !== modifiedArray[j].type) {
if (i ===originalArray.length - 1 && j === modifiedArray.length - 1) {
resultingArray.push({
sys_id: originalArray[i].sys_id,
type: modifiedArray[j].type,
action: 'add'
});
} else if (j === modifiedArray.length - 1) {
resultingArray.push({
sys_id: originalArray[i].sys_id,
type: originalArray[i].type,
action: 'remove'
});
}
}
}
}
console.log(resultingArray);
您可以将数组转换为字典。然后迭代原始字典并检查修改后的字典以找到 remove/edit/same
,然后迭代修改后的字典与原始字典以找到 add
项。 Concat 两次迭代的结果得到结果:
var originalArray = [{"sys_id":1234,"type":"XYZZ"},{"sys_id":1235,"type":"ABCD"},{"sys_id":1236,"type":"IJKL"},{"sys_id":1237,"type":"WXYZ"},{"sys_id":1238,"type":"LMNO"}];
var modifiedArray = [{"sys_id":1234,"type":"XYZZ"},{"sys_id":1235,"type":"ZZAA"},{"sys_id":1236,"type":"ZZZZ"},{"sys_id":1252,"type":"AAAA"}];
// create a dictionary of objects by the sys_id
function bySysId(arr) {
return arr.reduce(function(r, o) {
r[o.sys_id] = o;
return r;
}, {});
}
// add an action to an object
function addAction(o, action) {
var c = {
sys_id: o.sys_id,
type: o.type,
action: action
};
return c;
}
function diffArrays(original, modified) {
var origById = bySysId(original); // create a dictionary of original by sys_id
var modById = bySysId(modified); // create a dictionary of modified by sys_id
// iterate original and action
var modifiedOrSame = original.map(function(o) {
var mod = modById[o.sys_id];
if(!mod) return addAction(o, 'remove'); // doesn't exist in modById
else if(mod && mod.type !== o.type) return addAction(mod, 'edit'); // exists in modified but type is different
return addAction(o, 'same'); // haven't changed
});
var added = modified
.filter(function(o) { // remove items that are in original
return !(o.sys_id in origById);
})
.map(function(o) { // add the 'add' action to the items
return addAction(o, 'add');
});
return modifiedOrSame.concat(added);
}
var result = diffArrays(originalArray, modifiedArray);
console.log(result);
也许,这是最简单的解决方案,它完全支持ES5!
首先,将 originalArray
的所有项目推入 resultingArray
并包含 属性
action
= 'remove'
此外,将 resultingArray
的元素索引保存到可哈希对象中,其中 key
= sys_id
之后遍历 modifiedArray
个元素,如果 sys_id
已经存在于 resultingArray
中,则检查 hash
。如果已经存在,比较type
。否则,插入一个新元素,其中 action
= 'add'
我觉得我的代码比上面的描述更容易理解。开始了:
var originalArray = [{ sys_id: 1234, type: 'XYZZ' },{ sys_id: 1235, type: 'ABCD' },{ sys_id: 1236, type: 'IJKL' },{ sys_id: 1237, type: 'WXYZ' },{ sys_id: 1238, type: 'LMNO' }];
var modifiedArray = [{ sys_id: 1234, type: 'XYZZ' },{ sys_id: 1235, type: 'ZZAA' },{ sys_id: 1236, type: 'ZZZZ' },{ sys_id: 1252, type: 'AAAA' }];
var resultingArray = [],
hash = {},
index = 1;
originalArray.forEach(function(elem) {
var item = JSON.parse(JSON.stringify(elem));
item['action'] = 'remove';
resultingArray.push(item);
hash[item.sys_id] = index++;
});
modifiedArray.forEach(function(elem) {
index = hash[elem.sys_id];
if(index){
var item = resultingArray[index - 1];
item.action = (item.type === elem.type) ? 'same' : 'edit';
return;
}
var item = JSON.parse(JSON.stringify(elem));
item['action'] = 'add';
resultingArray.push(item);
});
console.log(resultingArray);
.as-console-wrapper {max-height:100% !important; top:0px;}
注意:在此解决方案中,假设 originalArray
的所有项目都是唯一的,modifiedArray
.
也是如此
我有两个数组 originalArray
和 modifiedArray
,它们的对象具有某些属性; sys_id
是独一无二的 属性:
originalArray = [
{ sys_id: 1234, type: 'XYZZ' },
{ sys_id: 1235, type: 'ABCD' },
{ sys_id: 1236, type: 'IJKL' },
{ sys_id: 1237, type: 'WXYZ' },
{ sys_id: 1238, type: 'LMNO' }
]
modifiedArray = [
{ sys_id: 1234, type: 'XYZZ' },
{ sys_id: 1235, type: 'ZZAA' },
{ sys_id: 1236, type: 'ZZZZ' },
{ sys_id: 1252, type: 'AAAA' }
]
我正在寻找 combine/merge 数组,但包括一个新的 属性,它描述了使用 sys_id 基于原始数组的新数组中更改内容的完整说明属性.
resultingArray = [
{ sys_id: 1234, type: 'XYZZ', action: 'same' },
{ sys_id: 1235, type: 'ZZAA', action: 'edit' },
{ sys_id: 1236, type: 'ZZZZ', action: 'edit' },
{ sys_id: 1237, type: 'WXYZ', action: 'remove' },
{ sys_id: 1238, type: 'LMNO', action: 'remove' },
{ sys_id: 1252, type: 'AAAA', action: 'add' }
还想知道是否有更合适的术语,或者更简洁的方式来解释我在这里试图完成的事情?
我在一个仅限于 ES5 的平台上。
遍历第一个数组,在第二个数组中找到相应的值并基于该生成元素。最后,将剩余的元素添加为新添加的。
var originalArray = [{ sys_id: 1234, type: 'XYZZ' }, { sys_id: 1235, type: 'ABCD' }, { sys_id: 1236, type: 'IJKL' }, { sys_id: 1237, type: 'WXYZ' }, { sys_id: 1238, type: 'LMNO' } ],
modifiedArray = [{ sys_id: 1234, type: 'XYZZ' }, { sys_id: 1235, type: 'ZZAA' }, { sys_id: 1236, type: 'ZZZZ' }, { sys_id: 1252, type: 'AAAA' } ];
// keep a swallow copy to not effect the original one
let mA = modifiedArray.slice();
// iterate over to generate new array
let res = originalArray.map(o => {
// get index of eleemnt
let moi = mA.findIndex(o1 => o1.sys_id === o.sys_id);
// if found
if (moi > -1) {
// remove it from the swallow copied array
let mo = mA.splice(moi,1)[0];
// check and generate new array
return { ...mo, action: mo.type === o.type ? 'same' : 'edited' }
} else {
// if not found return as removed
return { ...o, action: 'removed' }
}
// add remaining values as added
}).concat(mA.map(o=>({...o, action: 'added'})))
console.log(res);
ES5 替代方案:
var originalArray = [{ sys_id: 1234, type: 'XYZZ' }, { sys_id: 1235, type: 'ABCD' }, { sys_id: 1236, type: 'IJKL' }, { sys_id: 1237, type: 'WXYZ' }, { sys_id: 1238, type: 'LMNO' } ],
modifiedArray = [{ sys_id: 1234, type: 'XYZZ' }, { sys_id: 1235, type: 'ZZAA' }, { sys_id: 1236, type: 'ZZZZ' }, { sys_id: 1252, type: 'AAAA' } ];
// function for copying properties to function
function copyProperty(from, to) {
for (var prop in from) {
if (from.hasOwnProperty(prop))
to[prop] = from[prop];
}
return to;
}
var mA = modifiedArray.slice();
var res = originalArray.map(function(o) {
var moi = -1;
// get index by iterating
for (var i = 0; i < mA.length; i++) {
if (mA[i].sys_id === o.sys_id) {
moi = i;
break;
}
}
if (moi != -1) {
var mo = mA.splice(moi, 1)[0];
return copyProperty(mo, { action: mo.type === o.type ? 'same' : 'edited' })
} else {
return copyProperty(o, { action: 'removed' })
}
})
// push remaining values
mA.forEach(function(o) {
res.push(copyProperty(o, { action: 'added' }))
})
console.log(res);
使用 Array#reduce()
生成使用 sys_id
作为键并具有属性 orig
和 mod
的对象,然后使用一个很好的旧 for in
循环来迭代它对象并在 2 种类型存在时进行比较,或者检查哪些类型不存在并将适当的数据推送到结果数组。
所有 ES5 兼容
var grouped = [originalArray, modifiedArray].reduce(function(acc, arr, i) {
var label = i === 0 ? 'orig' : 'mod';
for (var j = 0; j < arr.length; j++) {
var curr = arr[j], id = curr.sys_id;
acc[id] = acc[id] || {orig: null, mod: null };
acc[id][label] = curr;
}
return acc;
}, {});
var res = [];
function insertObj(o, act) {
var newObj = { action: act };
// iterate existing keys to add to new object
for (var k in o) {
if (o.hasOwnProperty(k)) {
newObj[k] = o[k]
}
}
res.push(newObj)
}
for (var key in grouped) {
var action, obj;
if (grouped.hasOwnProperty(key)) {
obj = grouped[key]
if (!obj.orig) {
insertObj(obj.mod, 'add');
} else if (!obj.mod) {
insertObj(obj.orig, 'remove')
} else {
action = obj.mod.type === obj.orig.type ? 'same' : 'edit';
insertObj(obj.mod, action)
}
}
}
console.log(res)
<script>
var originalArray = [
{ sys_id: 1234, type: 'XYZZ' },
{ sys_id: 1235, type: 'ABCD' },
{ sys_id: 1236, type: 'IJKL' },
{ sys_id: 1237, type: 'WXYZ' },
{ sys_id: 1238, type: 'LMNO' }
]
var modifiedArray = [
{ sys_id: 1234, type: 'XYZZ' },
{ sys_id: 1235, type: 'ZZAA' },
{ sys_id: 1236, type: 'ZZZZ' },
{ sys_id: 1252, type: 'AAAA' }
]
</script>
只不过是老式的蛮力做事方式。此外,确保原始输入没有突变也很重要。基本上,我遍历所有内容两次,并检查以下条件:
1) 相同 sys_id 和类型(操作:相同)
2) 相同 sys_id,不同类型(操作:编辑)
3) 不同 sys_id,不同类型(操作:删除)
4) 不同 sys_id,不同类型,对象存在于 modifiedArray 但不存在于 originalArray(操作:添加)
(在没有任何 ES6 的情况下写这个让我很痛苦)
var originalArray = [
{ sys_id: 1234, type: 'XYZZ' },
{ sys_id: 1235, type: 'ABCD' },
{ sys_id: 1236, type: 'IJKL' },
{ sys_id: 1237, type: 'WXYZ' },
{ sys_id: 1238, type: 'LMNO' }
];
var modifiedArray = [
{ sys_id: 1234, type: 'XYZZ' },
{ sys_id: 1235, type: 'ZZAA' },
{ sys_id: 1236, type: 'ZZZZ' },
{ sys_id: 1252, type: 'AAAA' }
];
var resultingArray = [];
for (var i = 0; i < originalArray.length; i++) {
for (var j = 0; j < modifiedArray.length; j++) {
if (originalArray[i].sys_id === modifiedArray[j].sys_id && originalArray[i].type === modifiedArray[j].type) {
resultingArray.push({
sys_id: originalArray[i].sys_id,
type: originalArray[i].type,
action: 'same'
});
break;
} else if (originalArray[i].sys_id === modifiedArray[j].sys_id && originalArray[i].type !== modifiedArray[j].type) {
resultingArray.push({
sys_id: originalArray[i].sys_id,
type: modifiedArray[j].type,
action: 'edit'
});
break;
} else if (originalArray[i].sys_id !== modifiedArray[j].sys_id && originalArray[i].type !== modifiedArray[j].type) {
if (i ===originalArray.length - 1 && j === modifiedArray.length - 1) {
resultingArray.push({
sys_id: originalArray[i].sys_id,
type: modifiedArray[j].type,
action: 'add'
});
} else if (j === modifiedArray.length - 1) {
resultingArray.push({
sys_id: originalArray[i].sys_id,
type: originalArray[i].type,
action: 'remove'
});
}
}
}
}
console.log(resultingArray);
您可以将数组转换为字典。然后迭代原始字典并检查修改后的字典以找到 remove/edit/same
,然后迭代修改后的字典与原始字典以找到 add
项。 Concat 两次迭代的结果得到结果:
var originalArray = [{"sys_id":1234,"type":"XYZZ"},{"sys_id":1235,"type":"ABCD"},{"sys_id":1236,"type":"IJKL"},{"sys_id":1237,"type":"WXYZ"},{"sys_id":1238,"type":"LMNO"}];
var modifiedArray = [{"sys_id":1234,"type":"XYZZ"},{"sys_id":1235,"type":"ZZAA"},{"sys_id":1236,"type":"ZZZZ"},{"sys_id":1252,"type":"AAAA"}];
// create a dictionary of objects by the sys_id
function bySysId(arr) {
return arr.reduce(function(r, o) {
r[o.sys_id] = o;
return r;
}, {});
}
// add an action to an object
function addAction(o, action) {
var c = {
sys_id: o.sys_id,
type: o.type,
action: action
};
return c;
}
function diffArrays(original, modified) {
var origById = bySysId(original); // create a dictionary of original by sys_id
var modById = bySysId(modified); // create a dictionary of modified by sys_id
// iterate original and action
var modifiedOrSame = original.map(function(o) {
var mod = modById[o.sys_id];
if(!mod) return addAction(o, 'remove'); // doesn't exist in modById
else if(mod && mod.type !== o.type) return addAction(mod, 'edit'); // exists in modified but type is different
return addAction(o, 'same'); // haven't changed
});
var added = modified
.filter(function(o) { // remove items that are in original
return !(o.sys_id in origById);
})
.map(function(o) { // add the 'add' action to the items
return addAction(o, 'add');
});
return modifiedOrSame.concat(added);
}
var result = diffArrays(originalArray, modifiedArray);
console.log(result);
也许,这是最简单的解决方案,它完全支持ES5!
首先,将 originalArray
的所有项目推入 resultingArray
并包含 属性
action
= 'remove'
此外,将 resultingArray
的元素索引保存到可哈希对象中,其中 key
= sys_id
之后遍历 modifiedArray
个元素,如果 sys_id
已经存在于 resultingArray
中,则检查 hash
。如果已经存在,比较type
。否则,插入一个新元素,其中 action
= 'add'
我觉得我的代码比上面的描述更容易理解。开始了:
var originalArray = [{ sys_id: 1234, type: 'XYZZ' },{ sys_id: 1235, type: 'ABCD' },{ sys_id: 1236, type: 'IJKL' },{ sys_id: 1237, type: 'WXYZ' },{ sys_id: 1238, type: 'LMNO' }];
var modifiedArray = [{ sys_id: 1234, type: 'XYZZ' },{ sys_id: 1235, type: 'ZZAA' },{ sys_id: 1236, type: 'ZZZZ' },{ sys_id: 1252, type: 'AAAA' }];
var resultingArray = [],
hash = {},
index = 1;
originalArray.forEach(function(elem) {
var item = JSON.parse(JSON.stringify(elem));
item['action'] = 'remove';
resultingArray.push(item);
hash[item.sys_id] = index++;
});
modifiedArray.forEach(function(elem) {
index = hash[elem.sys_id];
if(index){
var item = resultingArray[index - 1];
item.action = (item.type === elem.type) ? 'same' : 'edit';
return;
}
var item = JSON.parse(JSON.stringify(elem));
item['action'] = 'add';
resultingArray.push(item);
});
console.log(resultingArray);
.as-console-wrapper {max-height:100% !important; top:0px;}
注意:在此解决方案中,假设 originalArray
的所有项目都是唯一的,modifiedArray
.