Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a Set of user-defined objects in Javascript with a user-defined equality function?

Tags:

javascript

I am very new to Javascript and wondering if it is possible to create a Set of user-defined objects in a way that allows me to specify the function that is used to make equality comparisons?

Here's a contrived example just to illustrate the functionality that I'm looking for:

myClass = function(val){
                 var self = this;
                 self.val = val
                 self.equals = //used defined equals function 
           }

a = new myClass(1.0)
b = new myClass(2.0)
c = new myClass(2.0)

s = new Set() //does not have to be actual "Set"
s.add(a)
s.add(b)
s.add(c)

s.size === 2 //returns true
s.has(a) //returns true
s.has(b) //returns true
s.has(c) //returns true

I've found Set implementations (like this one), but it seems like are only designed for values, not user-defined objects. I suspect that there are other implementations that use === but this would not be useful in my case since I don't believe that I can override === either.

My question is very similar to this question. I'm posting it again since: a) I don't necessarily need a native ES6 solution and would be open to using a third party library. and b) it's been some time since that question was posted.

like image 390
Berk U. Avatar asked Mar 02 '26 06:03

Berk U.


1 Answers

If you would accept to work with/override valueOf, then you could proceed like this:

// Implementation of special Set:
function mySet() {
    var self = this;
    self.size = 0;
    // Use a private map that will be keyed by the valueOf() of each added item: 
    var map = new Map();
    self.add = function (item) {
        map.set(item.valueOf(), item);
        self.size = map.size;
    };
    self.has = function (item) {
        return map.has(item.valueOf());
    };
    self[Symbol.iterator] = function* () {
        for (var pair of map) {
            yield pair[1]; // return the item ( not the valueOf() in [0])
        }
    };
    // etc...
}

// Test code:
myClass = function(val){
                 var self = this;
                 self.val = val;
                 self.valueOf = function () { return self.val; }; 
           }

a = new myClass(1.0);
b = new myClass(2.0);
c = new myClass(2.0);

s = new mySet(); //does not have to be actual "Set"
s.add(a);
s.add(b);
s.add(c);

document.write('size: ' + s.size + '<br>');
document.write('has(a): ' + s.has(a) + '<br>');
document.write('has(b): ' + s.has(b) + '<br>');
document.write('has(c): ' + s.has(c) + '<br>');

for (item of s) {
    document.write('stored item: ' + JSON.stringify(item) + '<br>');
};

Edit

Months later, I answered a similar question, where I did not suggest the use of valueOf, but a function that could be provided to the MySet constructor, defaulting to JSON.stringify.

like image 176
trincot Avatar answered Mar 04 '26 18:03

trincot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!