Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using RxJs groupBy with objects as keys

I'm trying to use groupBy with RxJs, and I need to use objects as keys. If I don't and I use, for example, simple strings like this:

var types = stream.groupBy(
    function (e) { return e.x; }); //x is a string

then everything goes fine and my subscription is called once, and once only, for each different key. But if I try with objects, the subscription is called for each element from stream, even if a key happens to be the same as previous ones.

There is of course a problem about object equality, but this is where I get confused because I don't understant how to use the additional arguments for groupBy. The latest version of docs says there have a 3rd argument that can be a comparer, but it never gets called. Earlier docs talk about a key serializer which is a totally different idea, but neither ways work for me.

Looking at Rx source code, I see attempts to check for a getHashCode function, but I do not find and documentation about it. Code like this:

var types = stream.groupBy(
    function (e) {
        return { x: e.x, y: e.y };   //is this valid at all?
    },
    function (e) { return e; },
    function (...) { return ???; }); //what am I supposed to do here?

is what i'm trying to write, but no luck, and whatever I put for the 3rd callback is not called.

What's wrong here?

like image 398
Wasp Avatar asked Oct 31 '22 11:10

Wasp


1 Answers

The simplest solution is to make sure your key function returns a number or string. But if you really want to return an object as your key, then you can use comparer and hashCode to help groupBy. Instead of hashCode (which requires you return a number), you can use valueOf which lets you return a string.

hashCode and valueOf should work similar to the c# Object.GetHashCode.

They should return a value such that:

  • Two keys that are considered equal should return the same value every time.
  • Two keys that are considered not equal should usually return a different value (to minimize collisions). The better you can ensure this, the more efficient the dictionary will be.

The difference is hashCode should return a number and valueOf can return a number or a string. Thus valueOf is easier to implement.

The rules for the comparer is that it takes 2 key values and should return true to indicate equality and false to indicate inequality.

So, you might write your example as:

var valueOf = function () {
    return JSON.stringify(this);
};

var keyCompare = function (a, b) { return a.x === b.x && a.y === b.y; };

var types = stream.groupBy(
    function (e) {
        return { x: e.x, y: e.y, valueOf: valueOf };   //is this valid at all?
    },
    function (e) { return e; },
    keyCompare);

But if your valueOf function is actually producing unique values that match your comparer and you don't really care about whether the key is tramsitted downstream as an actual object, then just make your life easier and transform your key into a string and use a string key like so:

var types = stream.groupBy(
    function (e) { return JSON.stringify({ x: e.x, y: e.y }); },
    function (e) { return e; });
like image 99
Brandon Avatar answered Nov 10 '22 15:11

Brandon