1996

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?

2
  • 33
    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.
    – janniks
    Commented Feb 3, 2020 at 12:05
  • 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. Commented May 6, 2020 at 13:06

91 Answers 91

1

For n arrays, you can get the union like so.

function union(arrays) {
    return new Set(arrays.flat()).keys();
};
1
1

Built a tester to check just how fast some of the performance oriented answers are. Feel free to add some more. So far, Set is both the simplest and fastest option (by bigger margins as the number of records increases), at least with simple Number types.

const records = 10000, //max records per array
  max_int = 100, //max integer value per array
  dup_rate = .5; //rate of duplication
let perf = {}, //performance logger,
  ts = 0,
  te = 0,
  array1 = [], //init arrays
  array2 = [],
  array1b = [],
  array2b = [],
  a = [];

//populate randomized arrays
for (let i = 0; i < records; i++) {
  let r = Math.random(),
    n = r * max_int;
  if (Math.random() < .5) {
    array1.push(n);
    r < dup_rate && array2.push(n);
  } else {
    array2.push(n);
    r < dup_rate && array1.push(n);
  }
}
//simple deep copies short of rfdc, in case someone wants to test with more complex data types
array1b = JSON.parse(JSON.stringify(array1));
array2b = JSON.parse(JSON.stringify(array2));
console.log('Records in Array 1:', array1.length, array1b.length);
console.log('Records in Array 2:', array2.length, array2b.length);

//test method 1 (jsperf per @Pitouli)
ts = performance.now();
for (let i = 0; i < array2.length; i++)
  if (array1.indexOf(array2[i]) === -1)
    array1.push(array2[i]); //modifies array1
te = performance.now();
perf.m1 = te - ts;
console.log('Method 1 merged', array1.length, 'records in:', perf.m1);
array1 = JSON.parse(JSON.stringify(array1b)); //reset array1

//test method 2 (classic forEach)
ts = performance.now();
array2.forEach(v => array1.includes(v) ? null : array1.push(v)); //modifies array1
te = performance.now();
perf.m2 = te - ts;
console.log('Method 2 merged', array1.length, 'records in:', perf.m2);

//test method 3 (Simplest native option)
ts = performance.now();
a = [...new Set([...array1, ...array2])]; //does not modify source arrays
te = performance.now();
perf.m3 = te - ts;
console.log('Method 3 merged', a.length, 'records in:', perf.m3);

//test method 4 (Selected Answer)
ts = performance.now();
a = array1.concat(array2); //does not modify source arrays
for (let i = 0; i < a.length; ++i) {
  for (let j = i + 1; j < a.length; ++j) {
    if (a[i] === a[j])
      a.splice(j--, 1);
  }
}
te = performance.now();
perf.m4 = te - ts;
console.log('Method 4 merged', a.length, 'records in:', perf.m4);

//test method 5 (@Kamil Kielczewski)
ts = performance.now();

function K(arr1, arr2) {
  let r = [],
    h = {};

  while (arr1.length) {
    let e = arr1.shift(); //modifies array1
    if (!h[e]) h[e] = 1 && r.push(e);
  }

  while (arr2.length) {
    let e = arr2.shift(); //modifies array2
    if (!h[e]) h[e] = 1 && r.push(e);
  }

  return r;
}
a = K(array1, array2);
te = performance.now();
perf.m5 = te - ts;
console.log('Method 5 merged', a.length, 'records in:', perf.m4);
array1 = JSON.parse(JSON.stringify(array1b)); //reset array1
array2 = JSON.parse(JSON.stringify(array2b)); //reset array2


for (let i = 1; i < 6; i++) {
  console.log('Method:', i, 'speed is', (perf['m' + i] / perf.m1 * 100).toFixed(2), '% of Method 1');
}

2
  • It seems there is a high sensibility to the number of items. For less than 400 items, on my machine (Mac with Chrome), Method 1 is fastest. For more, Method 3 is fastest. But since for small numbers performance is not important, and considering that Method 3 is by far the simplest to read, it should effectively be the recommended method.
    – Pitouli
    Commented Mar 1, 2021 at 2:07
  • 1
    I tested by replacing Numbers by Strings of text. And the result is still the same: method 1 is faster for small datasets (less than 50 items with the Strings), and Set is incredibly faster when size increase. gist.github.com/Pitouli/3165d59ae3a1fb90bf35ee7dbbebc28f
    – Pitouli
    Commented Mar 1, 2021 at 2:41
1

To offer something simpler and more elegant, in this day and age, using an existing library:

import {pipe, concat, distinct} from 'iter-ops';

// our inputs:
const array1 = ['Vijendra', 'Singh'];
const array2 = ['Singh', 'Shakya'];

const i = pipe(
    array1,
    concat(array2), // adding array
    distinct() // making it unique
);

console.log([...i]); //=> ['Vijendra', 'Singh', 'Shakya']

It is both high performance, as we are iterating only once, and the code is very easy to read.

P.S. I'm the author of iter-ops.

1
  • 1
    I'm trying this out, thanks for the lib bro
    – X3R0
    Commented Nov 23, 2021 at 14:13
1

Using Array.prototype.flat():

const input = [
  [1, 2, 3, 1],
  [101, 2, 1, 10],
  [2, 1]
];

const union = (arr) => {
  return [  ...new Set( arr.flat() )  ];
}

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

1

We can concat method use to add two or more array

array1.concat(array2, array3, ..., arrayX)

// unique remove duplicates of array

console.log([...new Set([1, 2, 4, 4, 3])]); // [1, 2, 4, 3]
0

Here is my solution https://gist.github.com/4692150 with deep equals and easy to use result:

function merge_arrays(arr1,arr2)
{
   ... 
   return {first:firstPart,common:commonString,second:secondPart,full:finalString}; 
}

console.log(merge_arrays(
[
[1,"10:55"] ,
[2,"10:55"] ,
[3,"10:55"]
],[
[3,"10:55"] ,
[4,"10:55"] ,
[5,"10:55"]
]).second);

result:
[
[4,"10:55"] ,
[5,"10:55"]
]
0

Just wrote before for the same reason (works with any amount of arrays):

/**
 * Returns with the union of the given arrays.
 *
 * @param Any amount of arrays to be united.
 * @returns {array} The union array.
 */
function uniteArrays()
{
    var union = [];
    for (var argumentIndex = 0; argumentIndex < arguments.length; argumentIndex++)
    {
        eachArgument = arguments[argumentIndex];
        if (typeof eachArgument !== 'array')
        {
            eachArray = eachArgument;
            for (var index = 0; index < eachArray.length; index++)
            {
                eachValue = eachArray[index];
                if (arrayHasValue(union, eachValue) == false)
                union.push(eachValue);
            }
        }
    }

    return union;
}    

function arrayHasValue(array, value)
{ return array.indexOf(value) != -1; }
0
Array.prototype.pushUnique = function(values)
{
    for (var i=0; i < values.length; i++)
        if (this.indexOf(values[i]) == -1)
            this.push(values[i]);
};

Try:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
array1.pushUnique(array2);
alert(array1.toString());  // Output: Vijendra,Singh,Shakya
0

If, like me, you need to support older browsers, this works with IE6+

function es3Merge(a, b) {
    var hash = {},
        i = (a = a.slice(0)).length,
        e;

    while (i--) {
        hash[a[i]] = 1;
    }

    for (i = 0; i < b.length; i++) {
        hash[e = b[i]] || a.push(e);
    }

    return a;
};

http://jsperf.com/merge-two-arrays-keeping-only-unique-values/22

0

This is simple and can be done in one line with jQuery:

var arr1 = ['Vijendra', 'Singh'], arr2 =['Singh', 'Shakya'];

$.unique(arr1.concat(arr2))//one line

["Vijendra", "Singh", "Shakya"]
1
  • 6
    From jQuery documentation "Note that this only works on arrays of DOM elements, not strings or numbers." (api.jquery.com/jQuery.unique). The method has been deprecated.
    – Melanie
    Commented May 25, 2016 at 16:13
0

I came across this post when trying to do the same thing, but I wanted to try something different. I just made up the function below. I also had another variable, 'compareKeys', (array of keys) for doing shallow object comparison. I'm going to probably change it to a function in the future.

Anyway, I didn't include that part, because it doesn't apply to the question. I also put my code into the jsperf going around. Edited: I fixed my entry in jsperf. My function gets about 99k ops/sec compared to 140k.

To the code: I first make an array of the available indices and then eliminate them by iterating over the first array. Finally, I push in the 'left-overs' by using the trimmed down array of indices that didn't match between the two arrays.

http://jsperf.com/merge-two-arrays-keeping-only-unique-values/26

function indiceMerge(a1, a2) {
    var ai = [];
    for (var x = 0; x < a2.length; x++) {
        ai.push(x)
    };

    for (var x = 0; x < a1.length; x++) {
        for (var y = 0; y < ai.length; y++) {
            if (a1[x] === a2[ai[y]]) {
                ai.splice(y, 1);
                y--;
            }
        }
    }

    for (var x = 0; x < ai.length; x++) {
        a1.push(a2[ai[x]]);
    }

    return a1;
}
2
  • What does this do that's different?
    – djechlin
    Commented Jan 10, 2019 at 17:58
  • I wrote it with performance in mind. There are many ways to do what the OP wants, but performance is usually overlooked. You can check it out link for an updated one, three years later. @djechlin
    – David Kirk
    Commented Jan 11, 2019 at 19:53
0

Usage: https://gist.github.com/samad-aghaei/7250ffb74ed80732debb1cbb14d2bfb0

var _uniqueMerge = function(opts, _ref){
    for(var key in _ref)
        if (_ref && _ref[key] && _ref[key].constructor && _ref[key].constructor === Object)
          _ref[key] = _uniqueMerge((opts ? opts[key] : null), _ref[key] );
        else if(opts && opts.hasOwnProperty(key))
          _ref[key] = opts[key];
        else _ref[key] = _ref[key][1];
    return _ref;
}
0

The best and simplest way to do that is using the function "some()" of JavaScript that returns true or false indicating if the array contains the object's element. You can make this:

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

var array3 = array1;

array2.forEach(function(elementArray2){
    var isEquals = array1.some(function(elementArray1){
        return elementArray1 === elementArray2;
    })
    if(!isEquals){
        array3.push(elementArray2);
    }
});
console.log(array3);

The results:

["Vijendra", "Singh", "Shakya"]

ss you wish... without duplicate it...

1
  • What does "ss you wish" mean? Commented Oct 18, 2017 at 6:57
0
var a = [1,2,3]
var b = [1,2,4,5]

I like one liners. This will push distinct b elements to a

b.forEach(item => a.includes(item) ? null : a.push(item));

And another version that will not modify a

var c = a.slice();
b.forEach(item => c.includes(item) ? null : c.push(item));
0

If you're purely using underscore.js, it doesn't have unionWith, unionBy

you can try out : _.uniq(_.union(arr1, arr2), (obj) => obj.key) ( key is the key param of each object ) this should help to get unique after union of both arrays.

0

I think this works faster.

removeDup = a => {

    for (let i = a.length - 1; i >= 0; i--) {
        for (let j = i-1; j >= 0; j--) {
            if (a[i] === a[j])
                a.splice(j--, 1);
        }
    }

    return a;
}
0
   //1.merge two array into one array

   var arr1 = [0, 1, 2, 4];
   var arr2 = [4, 5, 6];

   //for merge array we use "Array.concat"

   let combineArray = arr1.concat(arr2); //output

   alert(combineArray); //now out put is 0,1,2,4,4,5,6 but 4 reapeat

   //2.same thing with "Spread Syntex"

   let spreadArray = [...arr1, ...arr2];

   alert(spreadArray);  //now out put is 0,1,2,4,4,5,6 but 4 reapete


   /*
       if we need remove duplicate element method use are
       1.Using set
       2.using .filter
       3.using .reduce
   */
0

Not Performant if you have extremely large lists, and this isnt for merging since many solutions already have been documented, but i solved my problems with this solution (since most solutions of array filtering apply to simple arrays)

const uniqueVehiclesServiced = 
  invoice.services.sort().filter(function(item, pos, ary) {
    const firstIndex = invoice.services.findIndex((el, i, arr) => el.product.vin === item.product.vin)

  return !pos || firstIndex == pos;
});
0

I have a similar request but it is with Id of the elements in the array.

And, here is the way I do the deduplication.

It is simple, easy to maintain, and good to use.

// Vijendra's Id = Id_0
// Singh's Id = Id_1
// Shakya's Id = Id_2

let item0 = { 'Id': 'Id_0', 'value': 'Vijendra' };
let item1 = { 'Id': 'Id_1', 'value': 'Singh' };
let item2 = { 'Id': 'Id_2', 'value': 'Shakya' };

let array = [];

array = [ item0, item1, item1, item2 ];

let obj = {};
array.forEach(item => {
    obj[item.Id] = item;
});

let deduplicatedArray = [];
let deduplicatedArrayOnlyValues = [];
for(let [index, item] of Object.values(obj).entries()){
    deduplicatedArray = [ ...deduplicatedArray, item ];
    deduplicatedArrayOnlyValues = [ ...deduplicatedArrayOnlyValues , item.value ];
};
    
console.log( JSON.stringify(array) );
console.log( JSON.stringify(deduplicatedArray) );
console.log( JSON.stringify(deduplicatedArrayOnlyValues ) );

The console log

[{"recordId":"Id_0","value":"Vijendra"},{"recordId":"Id_1","value":"Singh"},{"recordId":"Id_1","value":"Singh"},{"recordId":"Id_2","value":"Shakya"}]

[{"recordId":"Id_0","value":"Vijendra"},{"recordId":"Id_1","value":"Singh"},{"recordId":"Id_2","value":"Shakya"}]

["Vijendra","Singh","Shakya"]
0

return an array of unique objects from arrays...

function uniqueObjectArray(baseArray, mergeArray) {
    // we can't compare unique objects within an array ~es6...
    // ...e.g. concat/destructure/Set()
    // so we'll create a mapping of: item.id* for each -> item
    const uniqueMap = new Map()
    const uniqueArray = []

    // hash array items by id*
    baseArray.forEach(item => !uniqueMap.has(item.id) && uniqueMap.set(item.id, item))
    mergeArray.forEach(item => !uniqueMap.has(item.id) && uniqueMap.set(item.id, item))

    // hash -> array
    uniqueMap.forEach(item => uniqueArray.push(item))
    return uniqueArray
}
0

My quick take

const arePropsEqualDefault = (oldProps, newProps) => {
  const uniqueKeys = Object.values({...Object.keys(oldProps), ...Object.keys(newProps)});
  for (const key in uniqueKeys) {
    console.log(Object.is(oldProps[key], newProps[key]))
    if (!Object.is(oldProps[key], newProps[key])) return false;
  }
  return true;
}
-1

This is the function I use when I need to merge, (or return the union of) two arrays.

var union = function (a, b) {
  for (var i = 0; i < b.length; i++)
    if (a.indexOf(b[i]) === -1)
      a.push(b[i]);
  return a;
};

var a = [1, 2, 3, 'a', 'b', 'c'];
var b = [2, 3, 4, 'b', 'c', 'd'];

a = union(a, b);
//> [1, 2, 3, "a", "b", "c", 4, "d"]

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

var array3 = union(array1, array2);
//> ["Vijendra", "Singh", "Shakya"]
-1
function set(a, b) {
  return a.concat(b).filter(function(x,i,c) { return c.indexOf(x) == i; });
}
-1

Better option for large inputs will be to sort arrays. Then merge them.

function sortFunction(a, b) {
        return a - b;
}

arr1.sort(sortFunction);
arr2.sort(sortFunction);

function mergeDedup(arr1, arr2) {

    var i = 0, j = 0, result = [];
    while (i < arr1.length && j < arr2.length) {

        if (arr1[i] < arr2[j]) {
            writeIfNotSameAsBefore(result, arr1[i]);
            i++;
        }
        else if (arr1[i] > arr2[j]) {
            writeIfNotSameAsBefore(result, arr2[j]);
            j++;
        }
        else {
            writeIfNotSameAsBefore(result, arr1[i]);
            i++;
            j++;
        }

    }

    while (i < arr1.length) {
        writeIfNotSameAsBefore(result, arr1[i]);
        i++;
    }

    while (j < arr2.length) {
        writeIfNotSameAsBefore(result, arr2[j]);
        j++;
    }
    return result;
}

function writeIfNotSameAsBefore(arr, item) {
    if (arr[arr.length - 1] !== item) {
        arr[arr.length] = item;
    }
    return arr.length;
}

Sorting will take O(nlogn + mlogm), where n and m are length of the arrays, and O(x) for merging, where x = Max(n, m);

-1

You can merge the results and filter the duplicates:

let combinedItems = [];

// items is an Array of arrays: [[1,2,3],[1,5,6],...]    
items.forEach(currItems => {
    if (currItems && currItems.length > 0) {
        combinedItems = combinedItems.concat(currItems);
    }
});

let noDuplicateItems = combinedItems.filter((item, index) => {
    return !combinedItems.includes(item, index + 1);
});
-1

/**
 * De-duplicate an array keeping only unique values.
 * Use hash table (js object) to filter-out duplicates.
 * The order of array elements is maintained.
 * This algorithm is particularly efficient for large arrays (linear time).
 */
function arrayUniqueFast(arr) {
	var seen = {};
	var result = [];
	var i, len = arr.length;
	for (i = 0; i < len; i++) {
		var item = arr[i];
		// hash table lookup
		if (!seen[item]) {
			result.push(item);
			seen[item] = true;
		}
	}
	return result;
}

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

var result = arrayUniqueFast(array1.concat(array2));
document.write('<br>result: ' + result);

For other methods to dedup an array, please see my benchmarks at: https://jsperf.com/de-duplicate-an-array-keeping-only-unique-values

-1

This is fast, collates any number of arrays, and works with both numbers and strings.

function collate(a){ // Pass an array of arrays to collate into one array
    var h = { n: {}, s: {} };
    for (var i=0; i < a.length; i++) for (var j=0; j < a[i].length; j++)
        (typeof a[i][j] === "number" ? h.n[a[i][j]] = true : h.s[a[i][j]] = true);
    var b = Object.keys(h.n);
    for (var i=0; i< b.length; i++)
        b[i]=Number(b[i]);
    return b.concat(Object.keys(h.s));
}

> a = [ [1,2,3], [3,4,5], [1,5,6], ["spoon", "fork", "5"] ]
> collate( a )

[1, 2, 3, 4, 5, 6, "5", "spoon", "fork"]

If you don't need to distinguish between 5 and "5", then

function collate(a){
    var h = {};
    for (i=0; i < a.length; i++) for (var j=0; j < a[i].length; j++)
        h[a[i][j]] = typeof a[i][j] === "number";
    for (i=0, b=Object.keys(h); i< b.length; i++)
        if (h[b[i]])
            b[i]=Number(b[i]);
    return b;
}
[1, 2, 3, 4, "5", 6, "spoon", "fork"]

will do.

And if you don't mind (or would prefer) all values ending up as strings anyway then just this:

function collate(a){
    var h = {};
    for (var i=0; i < a.length; i++)
        for (var j=0; j < a[i].length; j++)
            h[a[i][j]] = true;
    return Object.keys(h)
}
["1", "2", "3", "4", "5", "6", "spoon", "fork"]

If you don't actually need an array, but just want to collect the unique values and iterate over them, then (in most browsers (and node.js)):

h = new Map();
for (i=0; i < a.length; i++)
    for (var j=0; j < a[i].length; j++)
        h.set(a[i][j]);

It might be preferable.

1
  • 1
    Thank you so much. In synchronous jQuery operations this was that variation that worked for me for inline generated arrays. Commented Apr 8, 2016 at 11:30
-1

I learned a cheeky little way to concatenate two arrays with the spread operator:

var array1 = ['tom', 'dick', 'harry'];
var array2 = ['martin', 'ricky'];

array1.push(...array2);

The "..." spread operator splits the following array into individual items and then push can handle them as separate arguments.

1
  • 4
    interesting, but less readable than .concat() and doesn't resolve duplication issue
    – Serge P
    Commented Apr 9, 2018 at 18:10
-1

Given two sorted arrays of simple types without duplicates, this will merge them in O(n) time, and the output will be also sorted.

function merge(a, b) {
    let i=0;
    let j=0;
    let c = [];
    for (;;) {
        if (i == a.length) {
            if (j == b.length) return c;
            c.push(b[j++]);
        } else if (j == b.length || a[i] < b[j]) {
            c.push(a[i++]);
        } else {
            if (a[i] == b[j]) ++i;   // skip duplicates
            c.push(b[j++]);
        }
    }
}
2
  • What's different about this from the accepted answer and several other ~20 lines of raw JS answers?
    – djechlin
    Commented Jan 10, 2019 at 17:56
  • @djechlin it's different because, as I said in the description, it takes "sorted arrays of simple types" and it is pretty good because it is portable and O(n) which is faster than answers O(n^2). but no worries. i don't object to the down-vote! Commented Jan 11, 2019 at 19:04
-2

const merge(...args)=>(new Set([].concat(...args)))

1
  • Of coruse if you want to return an array then just use Array.from(merge(arguments)) Commented May 8, 2016 at 10:31

Not the answer you're looking for? Browse other questions tagged or ask your own question.