views:

841

answers:

5

I have two arrays in javascript like:

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

I want the output to be:

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

(Removing repeated words while merging the arrays).

A: 

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;
  };
meder
@Mender: Thanks it is working...
Vijjendra
@Mender: if order is not matter then how I do this
Vijjendra
There already is a `indexOf` method for arrays.
Gumbo
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.
meder
I wonder why this got selected instead of mine.
LiraNuna
Note that this algorithm is O(n^2).
Gumbo
What algorithm is your answer?
meder
@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).
Gumbo
@LiraNuna your solution doesn't seem to preserve the order. `[a,b,c]` and `[x,b,d]` would give `[a,c,x,b,d]` instead of `[a,b,c,x,d]`.
Amarghosh
did you find out what does `>>> 0` do in there? I can't think of an example where >>> 0 would make any difference.
Amarghosh
@Amarghosh: My solution wasn't posted after the OP's comment about order.
LiraNuna
Can any of you downvoters actually explain why you downvoted? My original solution solved the OP's issue, and my updated code does the same. The selected answer did not initially account for the ordering to which it was fixed later.
meder
It's unfair, this should definitely come on top of the jQuery one, at least.
Amarghosh
+13  A: 

To just merge the arrays (without removing duplicates) use Array.concat:

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

var array3 = array1.concat(array2); // Merges both arrays

Since there is no 'built in' way to remove duplicate (ECMA-262 actually has Array.forEach which would be great for this..), so we do it manually:

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).

LiraNuna
meh, forgot about `Array.prototype.concat` - good answer.
meder
Note that this algorithm is O(n^2).
Gumbo
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]`
Amarghosh
@Amarghosh: Fixed, that was posted before the OP's comment.
LiraNuna
OP accepted the first answer that got him working and signed off it seems. We are still comparing each others' solutions, finding-n-fixing faults, improving performance, making sure its compatible everywhere and so on... The beauty of stackoverflow :-)
Amarghosh
But I think it's worth it. I learned that w3schools is not the best reference out there, that `indexOf` is in fact present in js and how to add it for older browsers, and a new use for the `in` keyword (`from in this` part in the MDC version of indexOf, I didn't know that).
Amarghosh
+2  A: 
//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

Amarghosh
There already is a `indexOf` method for arrays.
Gumbo
I couldn't find it in w3schools, that's why I wrote it. http://www.w3schools.com/jsref/jsref_obj_array.asp Does it take a `from` parameter btw?
Amarghosh
@Amarghosh: W3CSchools is not a good reference. Use https://developer.mozilla.org instead.
Gumbo
@Gumbo Srsly? I've been using w3schools (and google) for normal js and MDC solely for FF extension related stuff. Gotta change that, huh?
Amarghosh
Seriously - w3schools is a horrible reference.
meder
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.
Amarghosh
MDC says indexOf requires javascript 1.6 Would it be safe to assume that the common browsers (>= FF2, > IE6 etc) would support it?
Amarghosh
IE6 doesn't support Array.prototype.indexOf, just paste the support method given by Mozilla so IE doesn't throw an error.
meder
updated using `indexOf`. Cleaned up the code by removing commented part. @meder - thanks again.
Amarghosh
+2  A: 

Why don't you use an object? It looks like you're trying to model a set. This wont 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
}
Nick Retallack
Don’t you mean `if (!set1.hasOwnProperty(key))`?
Gumbo
Why would I mean that? The purpose of that condition is to ignore properties that may be in the object's prototype.
Nick Retallack
A: 

This method uses an object called inserted to store the unique values from the arrays.

<html>
<body>
<script>
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var inserted = new Object();

function insert (array_in, array_out, inserted)
{
    for (var index in array_in) {
        var entry = array_in[index];
        if (!inserted[entry]) {
            inserted[entry] = true;
            array_out.push (entry);
        }
    }
}

function collate (array, inserted)
{
    for (var index in array)
        inserted[array[index]] = false;
}

var array3 = new Array ();
collate (array1, inserted);
collate (array2, inserted);
insert (array1, array3, inserted);
insert (array2, array3, inserted);

alert (array3);
</script>
</body>
</html>
Kinopiko