How to merge two arrays in JavaScript and de-duplicate items

Asked 2023-09-21 08:07:43 View 830,319

I have two JavaScript arrays:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

I want the output to be:

var array3 = ["Vijendra","Singh","Shakya"];

The output array should have repeated words removed.

How do I merge two arrays in JavaScript so that I get only the unique items from each array in the same order they were inserted into the original arrays?

  • Before you post a new answer, consider there are already 75+ answers for this question. Please, make sure that your answer contributes information that is not among existing answers. - anyone
  • If you want a more generic solution that also covers deep-merging, take a look at this question, instead. Some answers cover arrays as well. - anyone

Answers

To just merge the arrays (without removing duplicates)

ES5 version use Array.concat:

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];

array1 = array1.concat(array2);

console.log(array1);

2023 update

The original answer was from years ago. ES6 is fully supported and IE is finally dead. Here's the simplest way to merge primitive and object arrays:

const merge = (a, b, predicate = (a, b) => a === b) => {
    const c = [...a]; // copy to avoid side effects
    // add all items from B to copy C if they're not already present
    b.forEach((bItem) => (c.some((cItem) => predicate(bItem, cItem)) ? null : c.push(bItem)))
    return c;
}

merge(['a', 'b', 'c'], ['c', 'x', 'd']);
// => ['a', 'b', 'c', 'x', 'd']

merge([{id: 1}, {id: 2}], [{id: 2}, {id: 3}], (a, b) => a.id === b.id);
// [{id: 1}, {id: 2}, {id: 3}]

Original answer

ES6 version use destructuring

const array1 = ["Vijendra","Singh"];
const array2 = ["Singh", "Shakya"];
const array3 = [...array1, ...array2];

Since there is no 'built in' way to remove duplicates (ECMA-262 actually has Array.forEach which would be great for this), we have to do it manually. Note that this pollutes the Array prototype, use with caution.

Array.prototype.unique = function() {
    var a = this.concat();
    for(var i=0; i<a.length; ++i) {
        for(var j=i+1; j<a.length; ++j) {
            if(a[i] === a[j])
                a.splice(j--, 1);
        }
    }

    return a;
};

Then, to use it:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
// Merges both arrays and gets unique items
var array3 = array1.concat(array2).unique(); 

This will also preserve the order of the arrays (i.e, no sorting needed).

Since many people are annoyed about prototype augmentation of Array.prototype and for in loops, here is a less invasive way to use it:

function arrayUnique(array) {
    var a = array.concat();
    for(var i=0; i<a.length; ++i) {
        for(var j=i+1; j<a.length; ++j) {
            if(a[i] === a[j])
                a.splice(j--, 1);
        }
    }

    return a;
}

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
    // Merges both arrays and gets unique items
var array3 = arrayUnique(array1.concat(array2));

For those who are fortunate enough to work with browsers where ES5 is available, you can use Object.defineProperty like this:

Object.defineProperty(Array.prototype, 'unique', {
    enumerable: false,
    configurable: false,
    writable: false,
    value: function() {
        var a = this.concat();
        for(var i=0; i<a.length; ++i) {
            for(var j=i+1; j<a.length; ++j) {
                if(a[i] === a[j])
                    a.splice(j--, 1);
            }
        }

        return a;
    }
});

Answered   2023-09-21 08:07:43

  • Note that this algorithm is O(n^2). - anyone
  • Let [a, b, c] and [x, b, d] be the arrays (assume quotes). concat gives [a, b, c, x, b, d]. Wouldn't the unique()'s output be [a, c, x, b, d]. That doesn't preserve the order I think - I believe OP wants [a, b, c, x, d] - anyone
  • I originally up-voted this but have changed my mind. Assigning prototypes to Array.prototype has the consequences of breaking "for ... in" statements. So the best solution is probably to use a function like this but not assign it as a prototype. Some people may argue that "for ... in" statements shouldn't be used to iterate array elements anyway, but people often use them that way so at the very least this solution be used with caution. - anyone
  • you should always use for ... in with hasOwnProperty in which case the prototype method is fine - anyone
  • Just use Babel and Set() as described in another answer. - anyone

With Underscore.js or Lo-Dash you can do:

console.log(_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

http://underscorejs.org/#union

http://lodash.com/docs#union

Answered   2023-09-21 08:07:43

First concatenate the two arrays, next filter out only the unique items:

var a = [1, 2, 3], b = [101, 2, 1, 10]
var c = a.concat(b)
var d = c.filter((item, pos) => c.indexOf(item) === pos)

console.log(d) // d is [1, 2, 3, 101, 10]

Edit

As suggested a more performance wise solution would be to filter out the unique items in b before concatenating with a:

var a = [1, 2, 3], b = [101, 2, 1, 10]
var c = a.concat(b.filter((item) => a.indexOf(item) < 0))

console.log(c) // c is [1, 2, 3, 101, 10]

Answered   2023-09-21 08:07:43

  • The original solution here has the benefit of removing dupes within each source array. I guess it depends on your context which you would use. - anyone
  • You could merge different for IE6-support: c = Array.from(new Set(c)); - anyone
  • If I want to actually change a to add b, will it then be better to loop through and use push? a.forEach(function(item){ if(a.indexOf(item)<0) a.push(item); }); - anyone
  • Just a reminder of the current browser usage caniuse.com/usage-table for people anxious about IE6. - anyone
  • @Andrew: Even better: 1. var c = [...a, ...b.filter(o => !~a.indexOf(o))]; 2. var c = [...new Set([...a, ...b])]; ☺ - anyone
[...array1,...array2] //   =>  don't remove duplication 

OR

[...new Set([...array1 ,...array2])]; //   => remove duplication

Answered   2023-09-21 08:07:43

  • 1st/2nd example is no union at all + 1st example blows up the stack for large Arrays + 3rd example is incredibly slow and consumes a lot of memory, since two intermediate Arrays have to be build + 3rd example can only be used for union with a known number of Arrays at compile time. - anyone
  • so how you would do it ? - anyone
  • Note that for set can't deduplicate two objects that have the same key value pairs unless they are the same object references. - anyone
  • should be accepted answer for the modern of Javascript. - anyone
  • Does not work with an array of objects, as it'll only merge object references and doesn't care if the objects themselves are equal. - anyone

This is an ECMAScript 6 solution using spread operator and array generics.

Currently it only works with Firefox, and possibly Internet Explorer Technical Preview.

But if you use Babel, you can have it now.

const input = [
  [1, 2, 3],
  [101, 2, 1, 10],
  [2, 1]
];
const mergeDedupe = (arr) => {
  return [...new Set([].concat(...arr))];
}

console.log('output', mergeDedupe(input));

Answered   2023-09-21 08:07:43

  • This should be added to the accepted answer. This solution is much more efficient and much more elegant than what's currently possible but it's what we'll inevitably be able to do (and should do to keep up in this field). - anyone
  • Hard to say that this should be the accepted answer since the question is from 2009. But yes, this not only is more "performant" but also "elegant" - anyone
  • Array.from can be used instead of spread operator: Array.from(new Set([].concat(...arr))) - anyone
  • This is very elegant. Unfortunately Typescript doesn't support this yet. stackoverflow.com/questions/33464504/… - anyone
  • why not just return [...new Set(arr)]; rather than return [...new Set([].concat(...arr))];? Not saying it is wrong just wondering why you have to do this - anyone

Using a Set (ECMAScript 2015), it will be as simple as that:

const array1 = ["Vijendra", "Singh"];
const array2 = ["Singh", "Shakya"];
console.log(Array.from(new Set(array1.concat(array2))));

Answered   2023-09-21 08:07:43

  • I Consider this the "Accepted Answer" for using ES6. - anyone
  • @mwieczorek How about: const array3 = [...new Set(array1.concat(array2))] - anyone
  • It doesn't work if you are using an Array of objects - anyone
  • for merging different objects without duplicating : stackoverflow.com/a/54134237/3131433 - anyone

You can do it simply with ECMAScript 6,

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [...new Set([...array1 ,...array2])];
console.log(array3); // ["Vijendra", "Singh", "Shakya"];
  • Use the spread operator for concatenating the array.
  • Use Set for creating a distinct set of elements.
  • Again use the spread operator to convert the Set into an array.

Answered   2023-09-21 08:07:43

  • I get error: Type 'Set<string>' is not an array type. - anyone
  • And if you for some reason don't want to use the spread operator, there's also: Array.from(new Set(array1.concat(array2))). - anyone
  • @gattsbr, with TypeScript in tsconfig.json, you can add "downlevelIteration": true to compilerOptions. - anyone

Here is a slightly different take on the loop. With some of the optimizations in the latest version of Chrome, it is the fastest method for resolving the union of the two arrays (Chrome 38.0.2111).

JSPerf: "Merge two arrays keeping only unique values" (archived)

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [];

var arr = array1.concat(array2),
  len = arr.length;

while (len--) {
  var itm = arr[len];
  if (array3.indexOf(itm) === -1) {
    array3.unshift(itm);
  }
}

while loop: ~589k ops/s
filter: ~445k ops/s
lodash: 308k ops/s
for loops: 225k ops/s

A comment pointed out that one of my setup variables was causing my loop to pull ahead of the rest because it didn't have to initialize an empty array to write to. I agree with that, so I've rewritten the test to even the playing field, and included an even faster option.

JSPerf: "Merge two arrays keeping only unique values" (archived)

let whileLoopAlt = function (array1, array2) {
    const array3 = array1.slice(0);
    let len1 = array1.length;
    let len2 = array2.length;
    const assoc = {};

    while (len1--) {
        assoc[array1[len1]] = null;
    }

    while (len2--) {
        let itm = array2[len2];

        if (assoc[itm] === undefined) { // Eliminate the indexOf call
            array3.push(itm);
            assoc[itm] = null;
        }
    }

    return array3;
};

In this alternate solution, I've combined one answer's associative array solution to eliminate the .indexOf() call in the loop which was slowing things down a lot with a second loop, and included some of the other optimizations that other users have suggested in their answers as well.

The top answer here with the double loop on every value (i-1) is still significantly slower. lodash is still doing strong, and I still would recommend it to anyone who doesn't mind adding a library to their project. For those who don't want to, my while loop is still a good answer and the filter answer has a very strong showing here, beating out all on my tests with the latest Canary Chrome (44.0.2360) as of this writing.

Check out Mike's answer and Dan Stocker's answer if you want to step it up a notch in speed. Those are by far the fastest of all results after going through almost all of the viable answers.

Answered   2023-09-21 08:07:43

  • There's a flaw in your methodology: you put the creation of array3 into the setup phase, while that cost should only be part of your while-based solution's score. With this 1 line moved, your solution falls to the speed of the for loop based one. I understand that array can be reused, but maybe the other algorithms could benefit too from not having to declare and initialize every necessary building block. - anyone
  • I agree with your premise @doldt, but disagree with your results. There is a fundamental design flaw with the loop based removal of entries, in that you have to recheck the length of the array after you have removed items, resulting in a slower execution time. A while loop working backwards does not have these effects. Here is an example with removing as many setup variables as I can without changing their original answer too much: jsperf.com/merge-two-arrays-keeping-only-unique-values/19 - anyone
  • @slickplaid the linked tests are empty, and the next revision at jsperf hangs in the while loop. - anyone
  • @doldt I've addressed your concerns in my answer and added a proper updated test to it as well. Let me know if you agree with those results or not. Also, I added another better result using an associative array. - anyone
  • @slickplaid Thanks for setting up the extended perf page. Unless I'm missing something, the "whileLoopAlt2" function doesn't work? It creates a new array containing the first array, and the second array (in reverse order). To avoid confusion I've made another revision that removes the broken function. I also added an additional example: jsperf.com/merge-two-arrays-keeping-only-unique-values/22 - anyone

I simplified the best of this answer and turned it into a nice function:

function mergeUnique(arr1, arr2){
    return arr1.concat(arr2.filter(function (item) {
        return arr1.indexOf(item) === -1;
    }));
}

Answered   2023-09-21 08:07:43

  • I believe this is much cleaner than the accepted answer. Also it looks like filter is supported in ECMAScript 5.1 + which is pretty supported now. - anyone
  • this is so much more succinct. - anyone
  • one liner: const mergeUnique = (a, b) => a.concat(b.filter(v => a.indexOf(v) === -1)) - anyone
  • This does not remove dups from arr1, it only adds unique elements from arr2 - anyone
  • One can use findIndex for finding index of objects by their property values within the filter() function like so: const index = arr1.findIndex(i => i.id === item.id); - anyone

The ES6 offers a single-line solution for merging multiple arrays without duplicates by using destructuring and set.

const array1 = ['a','b','c'];
const array2 = ['c','c','d','e'];
const array3 = [...new Set([...array1,...array2])];
console.log(array3); // ["a", "b", "c", "d", "e"]

Answered   2023-09-21 08:07:43

  • This adds nothing to the identical answers already provided in 2016 - anyone
  • And does not work for arrays of objects - anyone

I know this question is not about array of objects, but searchers do end up here.

so it's worth adding for future readers a proper ES6 way of merging and then removing duplicates

array of objects:

var arr1 = [ {a: 1}, {a: 2}, {a: 3} ];
var arr2 = [ {a: 1}, {a: 2}, {a: 4} ];

var arr3 = arr1.concat(arr2.filter( ({a}) => !arr1.find(f => f.a == a) ));

// [ {a: 1}, {a: 2}, {a: 3}, {a: 4} ]

Answered   2023-09-21 08:07:43

Just steer clear of nested loops (O(n^2)), and .indexOf() (+O(n)).

function merge(a, b) {
  var hash = {};
  var i;
  
  for (i = 0; i < a.length; i++) {
    hash[a[i]] = true;
  }
  for (i = 0; i < b.length; i++) {
    hash[b[i]] = true;
  }
  return Object.keys(hash);
}

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];

var array3 = merge(array1, array2);

console.log(array3);

Answered   2023-09-21 08:07:43

  • That's pretty amazing, especially if you're doing strings. Numbers would need an additional step to keep them as such. This function heftily beats out all other options if you don't mind (or care) that everything is a string after you're finished. Nice job. Performance results here: jsperf.com/merge-two-arrays-keeping-only-unique-values/21 - anyone

Just throwing in my two cents.

function mergeStringArrays(a, b){
    var hash = {};
    var ret = [];

    for(var i=0; i < a.length; i++){
        var e = a[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    for(var i=0; i < b.length; i++){
        var e = b[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    return ret;
}

This is a method I use a lot, it uses an object as a hashlookup table to do the duplicate checking. Assuming that the hash is O(1), then this runs in O(n) where n is a.length + b.length. I honestly have no idea how the browser does the hash, but it performs well on many thousands of data points.

Answered   2023-09-21 08:07:43

  • Very nicely done. Beats out quite (if not all) of the other results on this page by leveraging the associative array and keeping out the looping of indexOf and other operations. jsperf.com/merge-two-arrays-keeping-only-unique-values/21 - anyone
  • Your "hash" is the String() function in javascript. Which might work for primitive values (albeit with collisions between types), but it's not a good fit for arrays of objects. - anyone
  • I use a similar solution, I allow passing a hashCode function or passing a string to identify a property in the object to use as the hash key. - anyone

EDIT:

The first solution is the fastest only when there are few items. When there are over 400 items, the Set solution becomes the fastest. And when there are 100,000 items, it is a thousand times faster than the first solution.

Considering that performance is important only when there is a lot of items, and that the Set solution is by far the most readable, it should be the right solution in most cases

The perf results below were computed with a small number of items


Based on jsperf, the fastest way (edit: if there are less than 400 items) to merge two arrays in a new one is the following:

for (var i = 0; i < array2.length; i++)
    if (array1.indexOf(array2[i]) === -1)
      array1.push(array2[i]);

This one is 17% slower:

array2.forEach(v => array1.includes(v) ? null : array1.push(v));

This one is 45% slower (edit: when there is less than 100 items. It is a lot faster when there is a lot of items):

var a = [...new Set([...array1 ,...array2])];

And the accepted answer's is 55% slower (and much longer to write) (edit: and it is several order of magnitude slower than any of the other methods when there are 100,000 items)

var a = array1.concat(array2);
for (var i = 0; i < a.length; ++i) {
    for (var j = i + 1; j < a.length; ++j) {
        if (a[i] === a[j])
            a.splice(j--, 1);
    }
}

https://jsbench.me/lxlej18ydg

Answered   2023-09-21 08:07:43

  • Thanks for this and putting the performance numbers in easy to understand ranked % figures. I was originally searching for Set based options because of simplicity. Given my datasets can get very large, performance is definitely a more important consideration! - anyone
  • Turns out Set is much faster, especially as the records increase (for Numbers at least). See runnable testers at stackoverflow.com/a/66129415/2578125. - anyone
  • @OXiGEN Yep, either the browser implementation of Set has been improved, or it depends of the type of data. I should have written my arrays initialization in my answer :( - anyone
Array.prototype.merge = function(/* variable number of arrays */){
    for(var i = 0; i < arguments.length; i++){
        var array = arguments[i];
        for(var j = 0; j < array.length; j++){
            if(this.indexOf(array[j]) === -1) {
                this.push(array[j]);
            }
        }
    }
    return this;
};

A much better array merge function.

Answered   2023-09-21 08:07:43

  • var test = ['a', 'b', 'c']; console.log(test); will print ["a", "b", "c", merge: function] - anyone
  • Excellent solution. I've updated the jsperf test posted above by @slickplaid (jsperf.com/merge-two-arrays-keeping-only-unique-values/3) and it looks like this is the fastest one of them. - anyone
  • @Cobra At the risk of sounding petty, running on Chrome 40.0.2214 (Latest as of 2/18/15), this answer is 53% slower than mine. OTOH IE11 seems not optimized for my answer at all. :) Chrome mobile is still rocking it, though. Honestly, if you're using lodash/_ which most of us should, the true answer is already pretty high up on this list. :) - anyone
  • @slickplaid True, and it's quite a bit faster, even compared to the lodash/_ one. I'll probably end up switching my implementation at one point or another to something similar to yours. :D - anyone
  • Not sure what the costs of indexOf() method are but this is probably the fastest ES5 compatible method. Also worth nothing that the variable length of arguments is not needed. This method is chainable. @slickplaid Loading a library is never an answer to a "how to do it in javascript" question. surely many libraries have a function to get this 7 lines job done. - anyone

Performance

Today 2020.10.15 I perform tests on MacOs HighSierra 10.13.6 on Chrome v86, Safari v13.1.2 and Firefox v81 for chosen solutions.

Results

For all browsers

  • solution H is fast/fastest
  • solutions L is fast
  • solution D is fastest on chrome for big arrays
  • solution G is fast on small arrays
  • solution M is slowest for small arrays
  • solutions E are slowest for big arrays

enter image description here

Details

I perform 2 tests cases:

  • for 2 elements arrays - you can run it HERE
  • for 10000 elements arrays - you can run it HERE

on solutions A, B, C, D, E, G, H, J, L, M presented in below snippet

// https://stackoverflow.com/a/10499519/860099
function A(arr1,arr2) {
  return _.union(arr1,arr2)
}

// https://stackoverflow.com/a/53149853/860099
function B(arr1,arr2) {
  return _.unionWith(arr1, arr2, _.isEqual);
}

// https://stackoverflow.com/a/27664971/860099
function C(arr1,arr2) {
  return [...new Set([...arr1,...arr2])]
}

// https://stackoverflow.com/a/48130841/860099
function D(arr1,arr2) {
  return Array.from(new Set(arr1.concat(arr2)))
}

// https://stackoverflow.com/a/23080662/860099
function E(arr1,arr2) {
  return arr1.concat(arr2.filter((item) => arr1.indexOf(item) < 0))
}


// https://stackoverflow.com/a/28631880/860099
function G(arr1,arr2) {
  var hash = {};
  var i;
  
  for (i = 0; i < arr1.length; i++) {
    hash[arr1[i]] = true;
  }
  for (i = 0; i < arr2.length; i++) {
    hash[arr2[i]] = true;
  }
  return Object.keys(hash);
}

// https://stackoverflow.com/a/13847481/860099
function H(a, b){
    var hash = {};
    var ret = [];

    for(var i=0; i < a.length; i++){
        var e = a[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    for(var i=0; i < b.length; i++){
        var e = b[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    return ret;
}



// https://stackoverflow.com/a/1584377/860099
function J(arr1,arr2) {
  function arrayUnique(array) {
      var a = array.concat();
      for(var i=0; i<a.length; ++i) {
          for(var j=i+1; j<a.length; ++j) {
              if(a[i] === a[j])
                  a.splice(j--, 1);
          }
      }

      return a;
  }

  return arrayUnique(arr1.concat(arr2));
}


// https://stackoverflow.com/a/25120770/860099
function L(array1, array2) {
    const array3 = array1.slice(0);
    let len1 = array1.length;
    let len2 = array2.length;
    const assoc = {};

    while (len1--) {
        assoc[array1[len1]] = null;
    }

    while (len2--) {
        let itm = array2[len2];

        if (assoc[itm] === undefined) { // Eliminate the indexOf call
            array3.push(itm);
            assoc[itm] = null;
        }
    }

    return array3;
}

// https://stackoverflow.com/a/39336712/860099
function M(arr1,arr2) {
  const comp = f => g => x => f(g(x));
  const apply = f => a => f(a);
  const flip = f => b => a => f(a) (b);
  const concat = xs => y => xs.concat(y);
  const afrom = apply(Array.from);
  const createSet = xs => new Set(xs);
  const filter = f => xs => xs.filter(apply(f));

  const dedupe = comp(afrom) (createSet);

  const union = xs => ys => {
    const zs = createSet(xs);  
    return concat(xs) (
      filter(x => zs.has(x)
       ? false
       : zs.add(x)
    ) (ys));
  }

  return union(dedupe(arr1)) (arr2)
}



// -------------
// TEST
// -------------

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

[A,B,C,D,E,G,H,J,L,M].forEach(f=> {
  console.log(`${f.name} [${f([...array1],[...array2])}]`);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>
  
This snippet only presents functions used in performance tests - it not perform tests itself!

And here are example test run for chrome

enter image description here

UPDATE

I remove cases F,I,K because they modify input arrays and benchmark gives wrong results

Answered   2023-09-21 08:07:43

  • why don't you improve the first snippet and remove the code duplication? - anyone
  • @Marco I don't know how to improve first snippet without loosing performance or simplicity - but I'm open to your solution - feel free to create new answer where you improve this solution in such way - everybody will be happy :) - anyone
  • @KamilKiełczewski : Careful! I have a strong suspicion that there is a bug in the test. When you add a console.log with the length of the arrays, you observe that the length is 0 in most cases. It feels like the array is not correctly reset between each run. And then of course, merging two null array is a very fast operation ;) This seems to be confirmed by this answer stackoverflow.com/a/66129415/2137476 where the K solution is fast, but less than the C solution (careful ; only look at the % comparaison; there is an error in the snippet and the chrono is wrong) - anyone
  • I confirm my suspicion. I updated the test bench so the array is parsed from an unmodified json. Obviously, every test is a bit slower, but it does not impact the ranking. And the K test is significantly slower than the C, D, L & M tests (on Mac Chrome). jsbench.me/mpklq0sj6l/1 - anyone
  • @Pitouli you are right - I update answer and remove solutions which changes input arrays F,I,K - because benchmark gives wrong results for it (when I have more time in future I will try to benchmark dropped solutions again) - anyone

Why don't you use an object? It looks like you're trying to model a set. This won't preserve the order, however.

var set1 = {"Vijendra":true, "Singh":true}
var set2 = {"Singh":true,  "Shakya":true}

// Merge second object into first
function merge(set1, set2){
  for (var key in set2){
    if (set2.hasOwnProperty(key))
      set1[key] = set2[key]
  }
  return set1
}

merge(set1, set2)

// Create set from array
function setify(array){
  var result = {}
  for (var item in array){
    if (array.hasOwnProperty(item))
      result[array[item]] = true
  }
  return result
}

Answered   2023-09-21 08:07:43

  • Don’t you mean if (!set1.hasOwnProperty(key))? - anyone
  • Why would I mean that? The purpose of that condition is to ignore properties that may be in the object's prototype. - anyone
  • It is not efficient to convert to objects in every use case. For example, we might want the union of keys from 2 arrays of Object.keys(). - anyone

For ES6, just one line:

a = [1, 2, 3, 4]
b = [4, 5]
[...new Set(a.concat(b))]  // [1, 2, 3, 4, 5]

Answered   2023-09-21 08:07:43

The best solution...

You can check directly in the browser console by hitting...

Without duplicate

a = [1, 2, 3];
b = [3, 2, 1, "prince"];

a.concat(b.filter(function(el) {
    return a.indexOf(el) === -1;
}));

With duplicate

["prince", "asish", 5].concat(["ravi", 4])

If you want without duplicate you can try a better solution from here - Shouting Code.

[1, 2, 3].concat([3, 2, 1, "prince"].filter(function(el) {
    return [1, 2, 3].indexOf(el) === -1;
}));

Try on Chrome browser console

 f12 > console

Output:

["prince", "asish", 5, "ravi", 4]

[1, 2, 3, "prince"]

Answered   2023-09-21 08:07:43

  • It does not remove duplicates from the output array. - anyone

My one and a half penny:

Array.prototype.concat_n_dedupe = function(other_array) {
  return this
    .concat(other_array) // add second
    .reduce(function(uniques, item) { // dedupe all
      if (uniques.indexOf(item) == -1) {
        uniques.push(item);
      }
      return uniques;
    }, []);
};

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var result = array1.concat_n_dedupe(array2);

console.log(result);

Answered   2023-09-21 08:07:43

  • It doesn't use anything that is new in ES6, did I miss something? - anyone
  • @Bergi: Yes, you are right. Thank you for noting. Somehow I was playing with this script and probably there was some version with ES6 function, but now it contains indexOf which is there for centuries. My mistake, sorry. - anyone

There are so many solutions for merging two arrays. They can be divided into two main categories(except the use of 3rd party libraries like lodash or underscore.js).

a) combine two arrays and remove duplicated items.

b) filter out items before combining them.

Combine two arrays and remove duplicated items

Combining

// mutable operation(array1 is the combined array)
array1.push(...array2);
array1.unshift(...array2);

// immutable operation
const combined = array1.concat(array2);
const combined = [...array1, ...array2];    // ES6

Unifying

There are many ways to unifying an array, I personally suggest below two methods.

// a little bit tricky
const merged = combined.filter((item, index) => combined.indexOf(item) === index);
const merged = [...new Set(combined)];

Filter out items before combining them

There are also many ways, but I personally suggest the below code due to its simplicity.

const merged = array1.concat(array2.filter(secItem => !array1.includes(secItem)));

Answered   2023-09-21 08:07:43

you can use new Set to remove duplication

[...new Set([...array1 ,...array2])]

Answered   2023-09-21 08:07:43

  • Note that this retain the order - anyone
  • Great solution for arrays of strings but won't work on array of objects. - anyone

You can achieve it simply using Underscore.js's => uniq:

array3 = _.uniq(array1.concat(array2))

console.log(array3)

It will print ["Vijendra", "Singh", "Shakya"].

Answered   2023-09-21 08:07:43

New solution ( which uses Array.prototype.indexOf and Array.prototype.concat ):

Array.prototype.uniqueMerge = function( a ) {
    for ( var nonDuplicates = [], i = 0, l = a.length; i<l; ++i ) {
        if ( this.indexOf( a[i] ) === -1 ) {
            nonDuplicates.push( a[i] );
        }
    }
    return this.concat( nonDuplicates )
};

Usage:

>>> ['Vijendra', 'Singh'].uniqueMerge(['Singh', 'Shakya'])
["Vijendra", "Singh", "Shakya"]

Array.prototype.indexOf ( for internet explorer ):

Array.prototype.indexOf = Array.prototype.indexOf || function(elt)
  {
    var len = this.length >>> 0;

    var from = Number(arguments[1]) || 0;
    from = (from < 0) ? Math.ceil(from): Math.floor(from); 
    if (from < 0)from += len;

    for (; from < len; from++)
    {
      if (from in this && this[from] === elt)return from;
    }
    return -1;
  };

Answered   2023-09-21 08:07:43

  • @Mender: if order is not matter then how I do this - anyone
  • It's not a standard ECMAScript method defined for Array.prototype, though I'm aware you can easily define it for IE and other browsers which don't support it. - anyone
  • Note that this algorithm is O(n^2). - anyone
  • What algorithm is your answer? - anyone
  • @meder: My algorithm is a union algorithm. The union itself is done in O(n+m), but sorting takes at most O(n·log n+m·log m). So the whole algorithm is O(n·log n+m·log m). - anyone

It can be done using Set.

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var array3 = array1.concat(array2);
var tempSet = new Set(array3);
array3 = Array.from(tempSet);

//show output
document.body.querySelector("div").innerHTML = JSON.stringify(array3);
<div style="width:100%;height:4rem;line-height:4rem;background-color:steelblue;color:#DDD;text-align:center;font-family:Calibri" > 
  temp text 
</div>

Answered   2023-09-21 08:07:43

//Array.indexOf was introduced in javascript 1.6 (ECMA-262) 
//We need to implement it explicitly for other browsers, 
if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(elt, from)
  {
    var len = this.length >>> 0;

    for (; from < len; from++)
    {
      if (from in this &&
          this[from] === elt)
        return from;
    }
    return -1;
  };
}
//now, on to the problem

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var merged = array1.concat(array2);
var t;
for(i = 0; i < merged.length; i++)
  if((t = merged.indexOf(i + 1, merged[i])) != -1)
  {
    merged.splice(t, 1);
    i--;//in case of multiple occurrences
  }

Implementation of indexOf method for other browsers is taken from MDC

Answered   2023-09-21 08:07:43

  • I couldn't find it in w3schools, that's why I wrote it. w3schools.com/jsref/jsref_obj_array.asp Does it take a from parameter btw? - anyone
  • Thanks @Gumbo and @meder - gonna change my bookmarks now. I'm yet to do anything serious in js and I use w3schools for casual reference (that's all I've ever needed) - may be that's why I didn't realize that. - anyone
  • MDC says indexOf requires javascript 1.6 Would it be safe to assume that the common browsers (>= FF2, > IE6 etc) would support it? - anyone
  • IE6 doesn't support Array.prototype.indexOf, just paste the support method given by Mozilla so IE doesn't throw an error. - anyone
  • updated using indexOf. Cleaned up the code by removing commented part. @meder - thanks again. - anyone
const array3 = array1.filter(t=> !array2.includes(t)).concat(array2)

Answered   2023-09-21 08:07:43

  • Please read How do I write a good answer?. While this code block may answer the OP's question, this answer would be much more useful if you explain how this code is different from the code in the question, what you've changed, why you've changed it and why that solves the problem without introducing others. - anyone
  • This question is nearly 13 years old and already has over 100 answers, including an accepted answer with a score of over 2,000. Are you entirely sure that this answer has not already been given? If so, please edit it to explain how it improves upon what is already here. - anyone
  • it is the best answer, already has a like - anyone
  • Seems like a pretty good answer to me. I'm glad the world doesn't work like SO too many rules that I can't be arsed to learn - anyone
Array.prototype.add = function(b){
    var a = this.concat();                // clone current object
    if(!b.push || !b.length) return a;    // if b is not an array, or empty, then return a unchanged
    if(!a.length) return b.concat();      // if original is empty, return b

    // go through all the elements of b
    for(var i = 0; i < b.length; i++){
        // if b's value is not in a, then add it
        if(a.indexOf(b[i]) == -1) a.push(b[i]);
    }
    return a;
}

// Example:
console.log([1,2,3].add([3, 4, 5])); // will output [1, 2, 3, 4, 5]

Answered   2023-09-21 08:07:43

array1.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)

The nice thing about this one is performance and that you in general, when working with arrays, are chaining methods like filter, map, etc so you can add that line and it will concat and deduplicate array2 with array1 without needing a reference to the later one (when you are chaining methods you don't have), example:

someSource()
.reduce(...)
.filter(...)
.map(...) 
// and now you want to concat array2 and deduplicate:
.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)
// and keep chaining stuff
.map(...)
.find(...)
// etc

(I don't like to pollute Array.prototype and that would be the only way of respect the chain - defining a new function will break it - so I think something like this is the only way of accomplish that)

Answered   2023-09-21 08:07:43

DeDuplicate single or Merge and DeDuplicate multiple array inputs. Example below.

useing ES6 - Set, for of, destructuring

I wrote this simple function which takes multiple array arguments. Does pretty much the same as the solution above it just have more practical use case. This function doesn't concatenate duplicate values in to one array only so that it can delete them at some later stage.

SHORT FUNCTION DEFINITION ( only 9 lines )

/**
* This function merging only arrays unique values. It does not merges arrays in to array with duplicate values at any stage.
*
* @params ...args Function accept multiple array input (merges them to single array with no duplicates)
* it also can be used to filter duplicates in single array
*/
function arrayDeDuplicate(...args){
   let set = new Set(); // init Set object (available as of ES6)
   for(let arr of args){ // for of loops through values
      arr.map((value) => { // map adds each value to Set object
         set.add(value); // set.add method adds only unique values
      });
   }
   return [...set]; // destructuring set object back to array object
   // alternativly we culd use:  return Array.from(set);
}

USE EXAMPLE CODEPEN:

// SCENARIO 
let a = [1,2,3,4,5,6];
let b = [4,5,6,7,8,9,10,10,10];
let c = [43,23,1,2,3];
let d = ['a','b','c','d'];
let e = ['b','c','d','e'];

// USEAGE
let uniqueArrayAll = arrayDeDuplicate(a, b, c, d, e);
let uniqueArraySingle = arrayDeDuplicate(b);

// OUTPUT
console.log(uniqueArrayAll); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 43, 23, "a", "b", "c", "d", "e"]
console.log(uniqueArraySingle); // [4, 5, 6, 7, 8, 9, 10]

Answered   2023-09-21 08:07:43

  • Why use arr.map here? You're using it as a foreach, as the result is ignored - anyone
  • I used return Array.from(set.values()); , because vscode gives error for return [...set]; - anyone