blob: 3f5d2c78a525e695f98b3d1c209316f146736380 [file] [log] [blame]
function existenceMap(array) {
var map = Object.create(null)
for (var i = 0, l = array.length; i < l; ++i) {
map[array[i]] = 1
}
return map
}
// Returns a list of operations to transform array a into array b. May not
// return the optimal set of operations.
module.exports = function patchArray(a, b) {
var ops = []
var workA = [].concat(a)
var inA = Object.create(null)
var itemA, cursorA, itemB, cursorB
var inB = existenceMap(b)
var posB = Object.create(null)
// First, check what was removed from a.
for (cursorA = 0; cursorA < workA.length;) {
itemA = workA[cursorA]
// If b does not contain the item, surely it must have been removed.
if (!inB[itemA]) {
workA.splice(cursorA, 1)
ops.push(['remove', cursorA])
}
// Otherwise, the item is still alive.
else {
inA[itemA] = true
cursorA += 1
}
}
// Then, check what was inserted into b.
for (cursorB = 0; cursorB < b.length; ++cursorB) {
itemB = b[cursorB]
// If a does not contain the item, it must have been added.
if (!inA[itemB]) {
workA.splice(cursorB, 0, itemB)
ops.push(['insert', cursorB, itemB])
}
posB[itemB] = cursorB
}
// At this point, workA contains the same items as b, but swaps may
// be needed.
for (cursorA = 0; cursorA < workA.length;) {
itemA = workA[cursorA]
var posInB = posB[itemA]
if (posInB === cursorA) {
cursorA += 1
}
else {
var temp = workA[posInB]
workA[posInB] = itemA
workA[cursorA] = temp
ops.push(['swap', cursorA, posInB])
}
}
return ops
}