0

This question is an extension of this one: Checking containment in set of lists in javascript. I want to be able to use a set like function in nodejs or Javascript that can support checking whether or not a list belongs to a collection. For example, given the example in the link, I would like the behavior:

var s = new SetWithListCheckingAbility([[1,2], [2,3]])
s.has([2, 3])
true

I was unable to find any nodejs library that has this functionality, however. The other obvious solution seems to be JSON serializing each object that is added to the set object, and doing checking based on the JSON string, since Javascript equality works for strings. This would probably require subclassing the Set object in ES6. However, I am not sure how to do this for this case...

Alex
  • 3,946
  • 11
  • 38
  • 66

2 Answers2

0

What you can do is take each member of the set and convert it to a string format (this answer looks like an elegant way to do that conversion from numbers to strings).

For your example, if you want s.has([3, 2]) to return false because [2,3] doesn't count as a match, the array to string conversion would look like array.join(','), otherwise array.sort().join(',') if order doesn't matter.

function setOfListsHasElement(theSet, theElement) {
  let newSet = new Set();
  theSet.forEach(e => newSet.add(e.join(',')) );
  return newSet.has(theElement.join(','));
}

Example usage:

var theSet = new Set();
theSet.add([1,2]);
theSet.add([2,3]);
setOfListsHasElement(theSet, [2,3]); // true
setOfListsHasElement(theSet, [3,2]); // false
setOfListsHasElement(theSet, [2,6]); // false
setOfListsHasElement(theSet, ["1", "2"]); // true - don't know how you want to handle scenarios like this, where the string representation of ["1", "2"] matches that of [1,2]
Pat Needham
  • 5,698
  • 7
  • 43
  • 63
  • That's going to be super slow though, since you have to recreate the local variable newSet every time you call the function. This was why I was thinking of subclassing the ES6 set class. – Alex Jul 01 '17 at 07:10
0

I figured out how to write a custom class that does what we want:

class SetImproved extends Set{
  constructor(){
    super();
    this.classDict = {};
    this._size = 0;
  }

  get size(){
    return this._size
  }

  add(x){
    if(!(JSON.stringify(x) in this.classDict)){
      this._size += 1;
    }
    this.classDict[JSON.stringify(x)] = x;
  }

  has(x){
    return JSON.stringify(x) in this.classDict;
  }

  delete(x){
    if(JSON.stringify(x) in this.classDict){
      this._size -= 1;
    }
    delete this.classDict[JSON.stringify(x)];
  }

  clear(){
    this.classDict = {};
  }

  keys(){
    return Object.keys(this.classDict).map(x => this.classDict[x]);
  }

  entries(){
    return Object.keys(this.classDict).map(x => this.classDict[x]);
  }

}

Some examples of the functionality:

var setImproved = new SetImproved()
setImproved.add([1, "b"])
setImproved.add([2, "c"])
setImproved.add(3)
setImproved.add("asdf")
console.log(setImproved.has([1, "b"]))
console.log(setImproved.has([3]))
setImproved.delete([4])
setImproved.delete([1, "b"])
console.log(setImproved.has(3))
console.log(setImproved.entries())
console.log(setImproved.size)
Alex
  • 3,946
  • 11
  • 38
  • 66