Created
November 13, 2013 17:53
-
-
Save pentaphobe/7453370 to your computer and use it in GitHub Desktop.
Iteratively merge arrays, preserving relative order
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This seems like a problem which can be solved more elegantly, but I needed this code today | |
* so despite a strong urge to sit down with pen and paper and relive my Godel, Escher, Bach days | |
* I must instead move along for now. | |
* | |
* | |
*/ | |
!function() { | |
/** | |
* Merge two arrays, maintaining order as much as possible | |
*/ | |
function mergeArrays(left, right) { | |
var result = [], | |
leftItem, rightItem, | |
leftIdx, rightIdx; | |
/** | |
* Early out for invalid arguments | |
* doesn't check type | |
*/ | |
if (!left || !right || (!left.length && !right.length)) { | |
return result; | |
} | |
/** | |
* Special case to iteratively reduce | |
*/ | |
if (arguments.length > 2) { | |
right = mergeArrays.apply(this, Array.prototype.slice.call(arguments, 1)); | |
} | |
// first add any data which precedes the first entry of left (ie. prepended to reference) | |
leftItem = left[0]; | |
rightIdx = right.indexOf(leftItem); | |
if (rightIdx !== -1) { | |
result = result.concat( right.slice(0, rightIdx) ); | |
right = right.slice(rightIdx); | |
} | |
// scan for matches | |
for (var i=0, max=left.length; i < max && right.length !== 0; i++) { | |
leftItem = left[i]; | |
rightItem = right[0]; | |
// same? simply insert | |
if (leftItem === rightItem) { | |
result.push(leftItem); | |
right = right.slice(1); | |
continue; | |
} | |
// otherwise, if it doesn't exist, simply add it | |
rightIdx = right.indexOf(leftItem); | |
if (rightIdx === -1) { | |
result.push(leftItem); | |
continue; | |
} | |
// otherwise inject whatever exists until that point, skipping | |
// anything which exists in the left | |
for (var j=0; j < rightIdx; j++) { | |
var rightItem = right[j]; | |
var leftIdx = left.indexOf(rightItem); | |
if (leftIdx === -1) { | |
result.push(rightItem); | |
} | |
} | |
right = right.slice(rightIdx); | |
// at this stage we don't actually want to step forward on the left array | |
i--; | |
} | |
// finally add any appended data from right | |
result = result.concat( right ); | |
return result; | |
} | |
var first = [ | |
'hello', | |
'foghorn', | |
'does not exist in second', | |
'leghorn' | |
]; | |
var second = [ | |
'prepended', | |
'hello', | |
'inserted first', | |
'foghorn', | |
'inserted second', | |
'inserted more', | |
'leghorn', | |
'appended' | |
]; | |
var third = [ | |
'inserted first', | |
'chickens', | |
'inserted more', | |
'appended', | |
'extra', | |
'stuff' | |
]; | |
var test = mergeArrays(first, second, third); | |
console.log(test); | |
}(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment