19

I have a set that I've added a list to.

var a = new Set();
a.add([1]);

Now I check if [1] exists in a:

a.has([1]);
> false

Based on the spec, this might be happening because if type is same for two objects being compared:

Return true if x and y refer to the same object. Otherwise, return false.

And this also happens:

[1] == [1]; 
> false

So it might be that the Set .has() is using == for comparing equality (not sure though). Is there a .contains() method for Set() in JS like Java has?

ShivanKaul
  • 687
  • 1
  • 8
  • 21
  • There is no something like that because there is no generic `equals` method for every object. You can take `set.values()` and use `some` method. (but then it's your responsibility on how you compare two arrays). – zerkms Aug 15 '16 at 23:38
  • `[1]` is an Array object _initializer_. Each time it is evaluated as an expression, a new Array object is created and initialized according to the "literal specifier" encountered. You can have a many different Array objects with equal valued elements in a Set as you like! – traktor Aug 16 '16 at 00:29

4 Answers4

30

You can't compare references like arrays and objects for equality (you can compare values, though).

The way you're doing it, you're checking against a different reference, even though the values appear to be the same.

Do something like this:

var a = new Set();
var b = [1];

a.add(b);

a.has(b); // => true

Take a look at MDN's Equality comparisons and sameness.

So it might be that the Set .has() is using == for comparing equality (not sure though)

Not necessarily. [1] === [1] (using the strict equality operator) also returns false.

Is there a .contains() method for Set() in JS like Java has?

Not in the way you're imagining it. You can do some sort of deep comparison, as mentioned in the first link in this answer.

Community
  • 1
  • 1
Josh Beam
  • 19,292
  • 3
  • 45
  • 68
5

although both [1]'s have the same value, they are two different arrays, pointing to two different locations in memory, hence they are not equal.

you can use a basic loop to check

for (let item of mySet.keys()) {
  item.toString() == [1].toString();
  //true on match.
}
Bamieh
  • 10,358
  • 4
  • 31
  • 52
0

If you compare two arrays with the "==" operator they will never be equals. They are different instance.

If you want using an array object :

  1. Define how two arrays are compared.
  2. Make a subclass of Set and override the "has" method.

.

function eqArray (a1, a2) {
    if (!(a1 instanceof Array && a2 instanceof Array))
      return false;
    if ( a1.length != a2.length)
      return false;
    for (var i = 0, n=a1.length; i < n; i++) {
        if (a1[i] instanceof Array && a2[i] instanceof Array) {
            if (!eqArray(a1[i], a2[i]))
                return false;       
        }           
        else if (a1[i] != a2[i])
            return false;       
    }       
    return true;
}

function MySet(elems) {
  var set = new Set (elems);
  set.__proto__ = MySet.prototype;
  return set;
}

MySet.prototype = new Set;

MySet.prototype.has = function (elem) {
   if (elem instanceof Array){
      for (var v of this) {
        if (v instanceof Array && eqArray(elem,v))
         return true;
      }
      return false;
   }else {
      return Set.prototype.has.call (this, elem);
   }
}

var a = new MySet();
a.add([1]);

a.has([1]); //true

eqArray([1],[1]); //true
fbohorquez
  • 168
  • 1
  • 4
  • 2
    Please don't suggest mutating global prototypes, that's absolutely terrible practice. If you need a special set, make a subclass, or some other wrapper object. – loganfsmyth Aug 16 '16 at 01:17
0

Ready to use it with any object you need. You just need to define how to compare them on a function

class SetDeep extends Set {
  constructor (elems){
    super(elems)
  }

  has(elem, compare) {
    if (compare instanceof Function) {
      return Array.from(this).some( setElem => compare(elem, setElem));
    } else {
      return super.has(elem);
    }
  }
}

Using fbohorquez eqArray:

function eqArray (a1, a2) {
  if (!(a1 instanceof Array && a2 instanceof Array))
    return false;
  if ( a1.length != a2.length)
    return false;
  for (var i = 0, n=a1.length; i < n; i++) {
      if (a1[i] instanceof Array && a2[i] instanceof Array) {
          if (!eqArray(a1[i], a2[i]))
              return false;
      }
      else if (a1[i] != a2[i])
          return false;
  }
  return true;
}

var a = new SetDeep();
var b = [1];

a.add(b);
a.has(b); // true

var c = new SetDeep();
c.add(b);

c.has([1]); // false
c.has([1], eqA) // true

With an object:

function equalId (a, b) {
  return a.id === b.id;
}

var objSet = new SetDeep([ { id: 'foo'}, {id: 'bar'} ]);

var foo = {id: 'foo' };

objSet.has(foo); // false;
objSet.has(foo, equalId); // true