How to merge arrays

JavaScript polyfill, by , Saturday, March 15th, 2014

Chances are, that you at some point need to merge two or more arrays together, and that by merging you mean that each entry in the merge resulting array is unique. If you do not care about uniqueness of entries, you simply need to concatenate the arrays, you can see how here in How to append arrays. There are many ways to approach this problem, and I will not attempt to cover everything here, but will show three ways to solve it, each of which view the task from a different angle. Each approach, can also be used on a single array, to remove repeated entries.

Merging arrays using a single for-loop

In this approach, as in the remaining two, we are going to write an unique() function to solve the problem. This function will return an array, which consists of the merged elements of the arrays given to it as parameters. (because this solution uses the Array.prototype.indexOf method, it will not work in older browsers such as IE8, but this is easily solved using a polyfill, and for this particular task, you can find a polyfill in Array.prototype.indexOf.)

  1. var uniqueMerge = function () {
  2. "use strict";
  3. var arg, arr, i, arrLen,
  4. a = [];
  5. if (arguments.length) {
  6. arg = Array.prototype.slice.call(arguments);
  7. arr = Array.prototype.concat.apply(arg.splice(0,1)[0], arg);
  8. arrLen = arr.length;
  9.  
  10. for (i = 0; i < arrLen; i += 1) {
  11. if (a.indexOf(arr[i]) < 0) {
  12. a.push(arr[i]);
  13. }
  14. }
  15. }
  16. return a;
  17. };

The way this works, is straight forward. At line 5 we check to make sure, that we have arguments passed to the function. If not, we just jump line 16 to return a which is an empty array. If on the other hand we have arguments, we proceed to; line 6 to turn the arguments into an array and to line 7 to concatenate an arbitrary number of passed arrays by calling the concat method using apply. From line 10 - 14 we iterate over the concatenated arrays checking, at line 11 if the current entry is already present in the array a, in which case it is not, we push it to it. Finally after iteration, we return a. This is a fine way of solving the task, and it has its elegance, but another, perhaps more interesting way, would be doing it using recursion.

Merging arrays using recursion

Solving problems using recursion, can prove both elegant and powerful, but perhaps more importantly, it can make otherwise difficult problems seem trivial. Solving this problem with recursion turned out to be really simple; (like the previous solution, this also uses Array.prototype.indexOf, so in case an important part of your visitors uses older IE browsers, get the polyfill linked to above.)

  1. var uniqueMerge = function () {
  2. "use strict";
  3. var arg = Array.prototype.slice.call(arguments),
  4. arr = Array.prototype.concat.apply(arg.splice(0,1)[0], arg),
  5. arrLen = arr.length;
  6. return (function makeUniqueArr (i, a) {
  7. return (i < arrLen) ? (function () {
  8. if (a.indexOf(arr[i]) < 0) {
  9. a.push(arr[i]);
  10. }
  11. return makeUniqueArr(i + 1, a);
  12. }()) : a;
  13. }(0, []));
  14. };

The first few lines in this approach is similar to the previous solution, so no need to look deeper into how that works. But at line 6 we see something different. Here we return the result on an self invoking function or more precisely an Immediately-Invoked Functional Expression. (IIFE) This particular function is given the name makeUniqueArr so that we can referrer back to it later. (making a recursive call) At line 7 we return one of two things depending on, if the iterator i is smaller than the length of the array arr or not. If i is smaller than arrLen we return the result of another IIFE that first checks if (at line 8) the current element (arr[i]) is already present in the array a, if not push it to it. Where after it returns the result of a recursive call to the makeUniqueArr function. If on the other hand, the iterator i is not smaller than arrLen it simply returns a, as it means we have iterated over all elements of arr

Merging arrays with a nested for-loop

This approach seems at the moment to be very popular, for reasons I do not fully understand, as it for me seems to do redundant iteration. But to go full circle on this particular problem, lets present it anyway;

  1. var uniqueMerge = function () {
  2. "use strict";
  3. var arg = Array.prototype.slice.call(arguments),
  4. arr = Array.prototype.concat.apply(arg.splice(0,1)[0], arg),
  5. i, j;
  6. for (i = 0; i < arr.length; i += 1) {
  7. for (j = i + 1; j < arr.length; j += 1) {
  8. if (arr[i] === arr[j]) {
  9. arr.splice(j--, 1);
  10. }
  11. }
  12. }
  13. return arr;
  14. };

What this approach does, is that it iterate over the concatenated arrays in two dimensions, first picking one element in the outer loop, then iterating over the following elements in the inner loop, checking if the outer element exists somewhere else in the array. If it does, it removes it. This means a lot of iteration, which could be costly if you have concatenated many big arrays.

Using the function

If we run the uniqueMerge function of any of the implementations, it will return us the merged array with unique entries.

  1. var numOne = [1, 2, 3, 4, 5],
  2. numTwo = [2, 4, 6, 7, 8],
  3. numThree = [0, 9, 7, 4];
  4.  
  5. // Prints out [1, 2, 3, 4, 5, 6, 7, 8, 0, 9]
  6. uniqueMerge(numOne, numTwo, numThree);