Open sffc opened 4 years ago
https://github.com/tc39/proposal-collection-normalization seems relevant.
@ljharb It seems collection normalization will convert the values but unique
proposal will not.
What i mean is, that approach could be used for a new collection hook that override the comparator (which defaults to SameValueZero)
Not sure how it could be used to override the comparator --- As I understand, it's not override the comparator but just change the values, so u may need a map to keep the mappings from the converted values to original values.
The normalization proposal can not, you’re correct. I’m suggesting the approach of “an options bag passed to the constructor that allows overriding internal algorithms”.
So it would be new Set(array, { comparator: (a, b) => a.id === b.id })
just as @sffc suggested? But as I understand, to make such usage efficient, very likely we finally also need write something close to hashCode
. And if that, it likely we need container type or equal/hash
protocol anyway, and make normalization not very useful 😅
I’m not sure why it wouldn’t be efficient as-is.
This is exactly what I thought when I read "new Set(array)
in ECMAScript 6 isn't enough for Non-primitive values" in the readme.
@hax No, it would be Array.from(new Map(array.map(x=>[x,x]), { coerceKey: x => x.id }).values())
or hopefully Array.from(new Set(array, { coerceKey: x => x.id }))
. An arbitrary comparator (not even an ordering one but just an equivalence one) cannot be used for efficient lookup.
I’m not sure why it wouldn’t be efficient as-is.
@ljharb Because comparator could be complex (eg. deep equal).
@bergus I think we have similar thought about that. comparator
by itself can't be efficient, but comparator
+ hashCode
could. To some degree, coerceKey
is like a stronger hashCode
which never have collisions.
As others have pointed out, we already have
[...new Set(array)]
for primitives. So, I think that the question this proposal is addressing can be generalized to, "use something other than===
to find duplicate objects in a Set".Here are a couple other potential ways to solve this problem off the top of my head (I haven't thought them through; these are just ideas):
[...new Set(array, { comparator: (a, b) => a.id === b.id })]
-- this would set a comparator on the Set to be used for all future additions to that specific Set.Object.prototype[@@setKey]
-- if present on an object,[@@setKey]
should be used instead of the object pointer when checking for equality in the Set.