New to ramda, building a mediator class I have an object describing registered (authorized) channels/messages. These channels are meant to be unique, both in their keys and values. At registering time, they are passed like this:
enum MyMessages {
FirstMessage = 'first:message',
SecondMessage = 'second:message'
};
mediator.addChannels(MyMessages); // With a validator to keep them unique.
To remove channels I call mediator.removeChannels(MyMessages);
.
The underlying imperative implementation works well:
// Makes a shallow clone of the existing channels.
let result = { ...existingChannels };
// Iterates the channels to remove.
for (const [key, value] of Object.entries(channelsToRemove)) {
// Keys match.
if (Object.keys(result).includes(key)) {
delete result[key];
}
// Values match.
if (Object.values(result).includes(value)) {
// Finds the key for the given value.
const k = Object.keys(result).find((a: string) => result[a] === value);
if (k) {
delete result[k];
}
}
// Channels to remove value matches an existing key.
if (Object.keys(result).includes(value as string)) {
delete result[value as string];
}
// Channels to remove key matches an existing value.
if (Object.values(result).includes(key)) {
const k = Object.keys(result).find((a: string) => result[a] === key);
if (k) {
delete result[k];
}
}
}
return result;
It's a bit naive and could be refactored, but at the end, I get my channels object without the keys / values that were removed.
I would like to replace this with ramda
functions.
I'm able to get overlapping keys with something like
R.without(R.keys(channelsToRemove), R.keys(existingChannels))
But I can't understand how I can easily get the final object (e.g. without the second object's keys or values).
const obj1 = {
foo: 'bar',
baz: 'sum'
}
const obj2 = {
baz: 'hop'
}
const obj3 = {
sum: 'ack'
}
As a result, I'd like this to happen:
obj1 - obj2
should return { foo: 'bar' }
: key overlaps key.obj1 - obj3
should return { foo: 'bar' }
: key overlaps value.obj2 - obj3
should return { baz: 'hop' }
: unique keys and values.This Ramda version looks to me like it does what you want:
const allDiff = (x, y) => fromPairs (filter (
none (flip (includes) ([...keys (y), ... map (String) (values (y) )]))
) (toPairs (x)))
const obj1 = {foo: 'bar', baz: 'sum'}
const obj2 = {baz: 'hop'}
const obj3 = {sum: 'ack'}
console .log (allDiff (obj1, obj2))
console .log (allDiff (obj1, obj3))
console .log (allDiff (obj2, obj3))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
<script>const {fromPairs, filter, none, flip, includes, keys, values, map, toPairs} = R</script>
We use toPairs -> filter -> fromPairs
to take apart our first object, filter the resulting key-value pairs, and then put it back together. The filter checks that neither element (none
) of our key-value
pair is included in (flip (includes)
) the list of element including the keys
or values
of our second object. We add map (String)
over the values in order to cover your value as string
. (I don't know TS well, but I'm guessing that this is equivalent.)
It's not clear to me, though, how much of an improvement this version is over a vanilla JS version:
const allDiff = (x, y,
props = [...Object .keys(y), ... Object .values(y) .map (String)],
fn = (v) => props .includes (v)
) => Object .fromEntries (
Object .entries (x) .filter (([k, v]) => !(fn(k) || fn (v)))
)
const allDiff = (x, y,
props = [...Object .keys(y), ... Object .values(y) .map (String)],
fn = (v) => props .includes (v)
) => Object .fromEntries (
Object .entries (x) .filter (([k, v]) => !(fn(k) || fn (v)))
)
const obj1 = {foo: 'bar', baz: 'sum'}
const obj2 = {baz: 'hop'}
const obj3 = {sum: 'ack'}
console .log (allDiff (obj1, obj2))
console .log (allDiff (obj1, obj3))
console .log (allDiff (obj2, obj3))
If you're already using Ramda, I think the Ramda one is a bit cleaner. But I don't think it's enough of an advantage that I would add Ramda to a codebase just for that.
While I'm sure we could make this entirely point-free with enough effort, I'm guessing that doing so would make it much less readable.