问题
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?
回答1:
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; });
来源:https://stackoverflow.com/questions/28000305/using-rxjs-groupby-with-objects-as-keys