Retrieve the object that is devoid of any keys or values present in another object within Ramda

Exploring ramda for the first time, I am creating a mediator class that involves an object detailing authorized channels and messages. These channels should be unique in both their keys and values. During registration, they are passed as follows:

enum MyMessages {
 FirstMessage = 'first:message',
 SecondMessage = 'second:message'
};

mediator.addChannels(MyMessages); // Ensuring uniqueness with a validator.

To delete channels, I use

mediator.removeChannels(MyMessages);
. The current imperative implementation functions properly:

// Creates a shallow copy of the existing channels.
let result = { ...existingChannels };
// Iterate through channels to be removed.
for (const [key, value] of Object.entries(channelsToRemove)) {
  // Matching keys.
  if (Object.keys(result).includes(key)) {
    delete result[key];
  }
  // Matching values.
  if (Object.values(result).includes(value)) {
    // Find the key corresponding to the value.
    const k = Object.keys(result).find((a: string) => result[a] === value);
    if (k) {
      delete result[k];
    }
  }
  // Value of channel to remove matches an existing key.
  if (Object.keys(result).includes(value as string)) {
    delete result[value as string];
  }
  // Key of channel to remove 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;

This code could benefit from refactoring, but ultimately achieves the goal of obtaining the updated channels object post deletion of keys / values.

I aim to replace this logic with ramda functions.

I can identify overlapping keys using something like

R.without(R.keys(channelsToRemove), R.keys(existingChannels))

However, I am facing challenges in figuring out how to obtain the final object easily (i.e., without the keys or values of the second object).

const obj1 = {
  foo: 'bar',
  baz: 'sum'
}

const obj2 = {
  baz: 'hop'
}

const obj3 = {
  sum: 'ack'
}

The desired outcome is as follows:

  • obj1 - obj2 should yield { foo: 'bar' }: key overlaps key.
  • obj1 - obj3 should give { foo: 'bar' }: key overlaps value.
  • obj2 - obj3 should produce { baz: 'hop' }: unique keys and values.

Answer №1

This specific implementation in Ramda appears to achieve the desired functionality:

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>

The approach used involves

toPairs -> filter -> fromPairs
, which deconstructs the first object into key-value pairs, filters them based on certain criteria, and then reconstructs the object. The filter operation ensures that neither the key nor the value of a key-value pair is present in the list of keys or values from the second object. Additionally, we use map (String) to convert values to strings as necessary.

Although the Ramda version may offer cleaner code compared to a basic JS alternative, the difference might not be significant enough to justify incorporating Ramda into a project solely for this purpose.

While it's possible to make this implementation entirely point-free with more effort, doing so could potentially sacrifice readability.

Answer №2

Using Ramda, a useful approach is to employ R.pickBy along with creating a custom predicate (as demonstrated in this Stack Overflow answer: ) that considers both the key and value of each property by utilizing R.unapply:

const {pipe, toPairs, flatten, map, flip, includes, none, unapply, curry, pickBy} = R

const getRemovePredicate = pipe(toPairs, flatten, map(String), flip(includes), none, unapply)

const allDiff = curry((obj, toRemove) => pickBy(
  getRemovePredicate(toRemove),
  obj
))

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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Adding files to an Angular ViewModel using DropzoneJS

I am facing a challenge in extracting file content and inserting it into a specific FileViewModel. This is necessary because I need to bundle all files with MainViewModel which contains a list of FileViewModel before sending it from the client (angular) to ...

Instead of relying on Vue TypeScript, we are leveraging IntelliJ with TypeScript 5.0.3 to compile our Vue project

My current version of IntelliJ IDEA is 2023.1 (Ultimate Edition) Build #IU-231.8109.175, released on March 28, 2023. I am facing an issue where my project fails to compile using "Vue TypeScript", resulting in some type mismatches being overlooked. In the ...

Employing async await for postponing the execution of a code block

I have been working on an Angular component where I need to perform some actions after a data service method returns some data asynchronously. Although I attempted to use async/await in my code, I feel that I may not have fully understood how it works. Her ...

Enriching HtmlElement with a type property using TypeScript

Check out my TypeScript code snippet below: let script: HTMLElement = document.createElement("script"); script.appendChild(document.createTextNode(` { "json": "property" } `)); script.id = 'appContextModel'; document.body.appendChild(scr ...

Is there a way to verify the functionality of this Angular 2 service?

In my Angular application, there is a service called BookService: import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; @Injectable() export class BookService { constructor(private http: Http) {} getL ...

How can a parent's method be activated only after receiving an event emitter from the child and ensuring that the parent's ngIf condition is met?

Every time the element in the child template is clicked, it triggers the method activateService(name) and emits an event with the name of the selected service using the event emitter serviceSelected. The parent component's method scrollDown(name) is t ...

Is it possible to apply filters to individual columns in a dynamic mat table using Angular?

Does anyone know how to add a filter for each dynamic column in an Angular Material table? I've only found solutions for static headers, but my table headers are constantly changing. I'm looking for something similar to this example: https://i.st ...

I'm confused why this particular method within a class is not being inherited by the next class. Rather than seeing the expected extension, I am presented with - [Function (

Working fine with the Person class, the register() function displays the correct return statement when logged in the console. However, upon extending it to the Employee class, instead of the expected return statement, the console logs show [Function (anon ...

Utilizing IonPage and DeepLinkMetadataType in Ionic 3 for tab navigation: Eliminating the need for tab-0

One of the pages on my site contains tabs that are only loaded when clicked: explore.html <ion-tabs> <ion-tab [root]="tab1Root" [tabTitle]="hotTitle" tabIcon="flame"></ion-tab> <ion-tab [root]="tab2Root" [tabTitle]="searchTitle ...

What is the most efficient way to organize a list within an object using functional programming, taking into account varying criteria for sorting depending on

In this scenario, we have an 'api_fetchData' function that retrieves data from the server. Depending on the route, the data can be in the form of a table or a tree structure. There are two states that need to be updated based on the received data ...

Webpack is mistakenly looking in the incorrect subfolder when attempting a relative import

I have set up a Vue application (version 3 with TypeScript) within a directory structure where the Vue app is nested inside a directory named /my-vue-app. In the same directory, there is a folder containing my Node.js server code (not TypeScript) that I am ...

Step-by-step guide for adding an object to a Material UI select component

I am in the process of incorporating a Select component with reactjs material ui and typescript. Yet, I encounter this typing error: Property 'id' does not exist on type 'string'. Property 'name' does not exist on type ' ...

Setting a default check on a checkbox within an ngFor loop in Angular 2

I'm attempting to initialize a default value as checked for a checkbox within my ngFor loop. Here is an array of checkbox items I am working with: tags = [{ name: 'Empathetic', checked: false }, { name: 'Smart money', che ...

Can an attribute be assigned to an Angular host element without specifying a value?

Exploring the concept of host binding on the input element's readonly attribute, aiming to add the attribute without assigning any value. Even though HTML specifications state that assigning a value may not make a difference as long as the attribute i ...

How to extract the first initials from a full name using Angular TypeScript and *ngFor

I am new to Angular and still learning about its functionalities. Currently, I am developing an Angular app where I need to display a list of people. In case there is no picture available for a person, I want to show the first letters of their first name a ...

How to apply dynamic values for filtering in TypeScript?

My task is to filter out all Portfolio Lead who have English Competency set to No. var data = [{ "Employee Number": 138, "English Competency": "No", "Portfolio Lead": "x", "Maths Competency": "No" }, { "Employee Number": 1385, ...

When trying to run ionic serve, I encountered the following error: "[ERROR] ng has unexpectedly closed with an exit code of 127."

My attempt to launch an ionic app on my Mac has hit a roadblock. While running npm install for the dependencies, everything goes smoothly without any issues. However, when I try to run 'ionic serve' or 'ionic s', an error crops up: [ng] ...

Sending data from view to controller in Angular using TypeScript

I am currently working with AngularJS and TypeScript, and I have encountered an issue with passing a parameter from the view to the controller. In my attempts to solve this problem, I have utilized ng-init as follows: <div class="col-md-9" ng-controlle ...

Perform a series of database queries one after the other, ensuring they are completed before

Although the database queries themselves are working fine, I am facing an issue with executing them sequentially in Node. Here is an example of the queries I need to execute in order: DELETE FROM myTable; INSERT INTO myTable(c1, c2, c3) VALUES (x, y, z); ...

Is there a way to identify the items that have been removed and added in an array by comparing an old array to a new array

Consider the following scenario: oldArray = [ { id: 1, position: 'DEV OM'}, { id: 2, position: 'Senior Developer'}, ] newArray = [ { id: 2, position: 'Senior Developer'}, { id: 3, position: 'Junior Devel ...