Using recursive functions in Javascript to modify or remove objects from an array by their unique identifier

I am attempting to develop two recursive functions to "iterate" over an array of objects as shown below. I believe the two functions are quite similar, but they serve different purposes.

Function 1 is designed to update the object - it can modify every field in the "found" object and then return the "new" array of objects. Therefore, the function needs to locate the appropriate object by its .id

Function 2 is meant to find the object based on its .id and delete that object from the array, before returning the updated array of objects.

I have experimented with various methods (below the array of objects) but unfortunately, I am unable to successfully return the new object.

It's worth noting that even if each object has different keys, there will always be an .id key.

[
    {
        "type":"section",
        "name":"Section 1",
        "hassection":[      
            {
                "type":"section",
                "id":1,
                "name":"Section 1 child section 1",
                "hasMenuItem":
                    [
                        {
                            "type":"item",
                            "id":2,
                            "name":"Item 1",
                            "prices":
                            {
                                "type":"price",
                                "price":"15.95"
                            },
                            "description":"Blah Blah..."
                        },{
                            "type":"item",
                            "id":3,"name":
                            "Item 2",
                            "prices":[
                                {
                                    "type":"price",
                                    "price":"24.95"
                                },{
                                    "type":"price",
                                    "price":"13.95"
                                }
                            ],
                            "description":"Blah Blah..."
                        }
                ]
            },{
                "type":"section",
                "id":4,
                "name":"Section 1 child section 2",
                "hasitem":[
                    {
                        "type":"item",
                        "name":"Item 3",
                        "prices":
                        {
                            "type":"price","price":"14.50"
                        },
                        "description":"Blah Blah..."
                    },{
                        "type":"item",
                        "id":5,
                        "name":"Item 4",
                        "prices":
                        {
                            "type":"price",
                            "price":"14.50"
                        },
                        "description":"Blah Blah..."
                    }
                ]
            },
        ]},{
            "type":"section",
            "name":"Section 2",
            "hassection":[      
                {
                    "type":"section",
                    "id":6,
                    "name":"Section 2 child section 1",
                    "hasitem":[
                        {
                            "type":"item",
                            "id":7,
                            "name":"Item 5",
                            "prices":
                            {
                                "type":"price",
                                "price":"15.95"
                            },
                            "description":"Blah Blah..."
                        },
                        {
                            "type":"item",
                            "id":8,
                            "name":"Item 6",
                            "prices":
                            {
                                "type":"price",
                                "price":"13.95"
                            },
                            "description":"Blah Blah..."
                        }
                    ]
            }
        ]}
    ]

My function for updating

function updateNestedObj(obj,updates) {
    const updateToApply = updates.find(upd => upd.id === obj.id);
    if (updateToApply) {
        // UPDATE THE OBJECT
    }
    
    for(let k in obj) {
        if (typeof(obj[k]) === 'object') {
            // ITERATE THROUGH THE OBJECT
            updateNestedObj(obj[k], updates);
        }
    }
    return updateToApply
}

My function for deleting

function deleteNestedObj(obj, updates) {
    const updateToApply = updates.find(upd => upd.id === obj.id);
    if (updateToApply) {
        delete upd;       
    }    
    for(let k in obj) {
        if (typeof(obj[k]) === 'object') {
            deleteNestedObj(obj[k], updates);
        }
    }
}

I am struggling to figure out how to properly implement these functions - any assistance would be greatly appreciated. Thank you in advance!

Answer №1

generics

Let's kick things off with an immutable function called update(t, func). This function accepts a value of any type, referred to as t, and a callable updater function, func. The purpose of func is to modify the value of

t</code based on the specified return value by the caller. If no value is returned (i.e., <code>undefined
), then the update function will essentially remove that specific value from the tree.

function update(t, func) {
  switch (t?.constructor) {
    case Object:
      return Object.entries(t).reduce((r, [k, v]) => {
        const newValue = update(func(v), func)
        if (newValue !== undefined) r[k] = newValue
        return r
      }, {})
    case Array:
      return t.flatMap(v => {
        const newValue = update(func(v), func)
        return newValue === undefined ? [] : [newValue]
      })
    default:
      return t
  }
}

The concept of an immutable function for remove(t, func) can be seen as a specialization of the update function.

function remove(t, func) {
  return update(t, v => Boolean(func(v)) ? undefined : v)
}

special forms

These functions can be further specialized to cater to your specific requirements. For instance, updateWithObj(t, obj) will recursively update the object t where a node's id matches the provided obj.id.

function updateWithObj(t, obj) {
  return update(t, v => v.id == obj.id ? {...v, ...obj} : v)
}

Similarly, removeWithObj(t, obj) recursively removes nodes from object t where a node's id matches obj.id.

function removeWithObj(t, obj) {
  return remove(t, v => v.id == obj.id)
}

examples

Let's generate some sample data for illustration purposes. It is worth noting that update is indifferent whether it deals with arrays of elements or individual objects.

const data = [
  {id: 1, data: 50 },
  {id: 2, data: {id: 3, data: "foo"}},
  {id: 4, data: [{id: 5, data: 3.141}, {id: 6, data: {id: 7, data: "bar"}}]}
]

We'll begin with a straightforward update operation on obj.id == 1. Observe how the existing data attribute remains unaltered while a new attribute ok is added. The other nodes remain unchanged.

console.log(updateWithObj(data, {id: 1, ok: "✅"}))
.... ....(truncated for brevity) ....

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

Exploring NodeJs integration with Google Geocoder API

I am currently developing a Geocoding web application using NodeJs. The geocoding functionality works well, however, I am encountering a 40% error rate of 620 from the Google API, resulting in a significant loss of addresses to be geocoded. The Error 620 ...

Should data be sent via ajax to the server before reloading the page to view the results, or is it more efficient to update the DOM using JavaScript?

Hello there, I am working on a Django (3.1) site that has some interactive features where users can add, edit, and delete comments using html/javascript code. Currently, when a user performs one of these actions, the script sends the data to the server vi ...

Why am I receiving a 404 error when trying to access an Angular 9 route within a subfolder

I am facing an issue with my Angular 9 app that is hosted in a domain subfolder. The problem lies in the index.html base tag, shown below: <base href="/subfolder/"> Everything works perfectly fine when the app is run locally without the ba ...

How to implement a cyclic item generation feature in React.js

My function is meant to draw multiple items in a cycle, but it is only drawing the first item when I attempt to draw 5. This is my function: export default function CinemaHole() { const items = []; for(let i = 0; i < 5; i++) { item ...

Validation for prototype malfunctioning

I am currently using Prototype.js to implement form validation on my website. One of the fields requires an ajax request to a PHP file for validation purposes. The PHP file will return '1' if the value is valid and '0' if it is not. Des ...

Changing the order of element names depending on their location within the parent element using jQuery

<div class="content"> <div> <input type="text" name="newname[name]0"/> <div> <input type="text" name="newname[utility]0"/> <div> <textarea name="newname[text]0 ...

The camera scene is experiencing difficulties in updating the image

Image not refreshing in a scene. I am using Javascript, Three, and CSS3DRenderer on my client within Chrome. I have embedded an image in a scene via a THREE.Object3D. When the image is updated on the server, it does not update in the scene. I have implemen ...

It appears that when importing from a shared package in lerna, the name must include "src" at the end for Typescript or Javascript files

I am currently working on a straightforward lerna project structure as shown below: Project | +-- packages | | | +-- shared | | | | | +-- src | | | | | +-- index.ts | | +-- someDir | | | +-- usesShared | ...

Arranging a Multi-layered Array Based on One of Its Values

Before anything else, I have reviewed and attempted the following links: Sort Multi-dimensional Array by Value Sort Multi-dimensional Array by Value Sort php multidimensional array by sub-value http://php.net/manual/fr/function.array-multisort.php. No ...

Using Jquery to duplicate a row from one table and insert it into another table

Recently, I've dived into the world of jQuery and JavaScript with the goal of creating a simple app. The main functionality I'm trying to implement is the ability to copy a row from one table to another and then delete the original row when a but ...

Managing the dropdown selection will reset the text field when the onchange event is triggered with the submission of the form

My form has multiple sections, and whenever I choose an answer from the dropdown in one section, it clears the data entered in another section. I am using the "onchange" event to display a calculation at the bottom of the form before submission. Section B ...

Where can I find the zip code that matches the State, city, and country in the USA?

For my Laravel project, I am in need of a comprehensive list of zip codes from the United States along with their corresponding city and state information in JSON or CSV format. Can anyone assist me with this data? ...

Encountering a discrepancy in the level of indirection error

Hey there, I just finished coding my project but when I tried to compile it, I encountered this error message: '<=': 'int' differs in levels of indirection from 'int *'. I'm a bit confused about what's going on he ...

"Mastering the art of event delegation: A guide to effectively engaging with various

I have data that is generated dynamically, as shown in the snippet below: const resultsDiv = document.getElementById("results"); const getList = document.getElementById("example"); document.querySelector(".container").addEventListener("click", function ...

Challenges with splitting asynchronous code in NPM modules

Earlier, I posted a query on Stack Overflow I have recently established a local package within the main app's package.json: "contact-page": "file:local_modules/contact-page" The package.jsonmain and scripts sections for the contact module are confi ...

"Utilizing Angular's ng-repeat to house multiple select dropdown

I'm dealing with a scenario like this: <span ng-repeat="personNum in unit.PricePerson"> {{personNum}} <select ng-model="personNum" ng-options="o as o for o in unit.PricePerson track by $index"></select> & ...

transferring data to Amazon Web Services using Angular framework

I'm currently facing an issue while trying to send a file to an AWS server using an Angular dropzone. I have my AWS credentials ready, but I am unsure of how to properly make the request. Every time I attempt to drop the file into the dropzone, I kee ...

The issue in jQuery arises from a syntax error within an array

Seeking assistance to identify the issue in the following code snippet: function cat_autocomplete(){ var categoryTags = ["boots>black","boots>brown>boys>blue","clothes>small_men>scarfs>blue","boots","boots>brown>boys","boots ...

Deactivating the idle timer in React Native: A Step-by-Step Guide

Currently, I am working on an app that involves a timer using RN. However, I have noticed that after approximately 1 minute and 50 seconds, the device's screen starts to dim in preparation for sleep mode. ...

Divide promise chain into individual functions

Split into two separate functions: public valJson(json, schemaFile: string) { return new Promise((resolve, reject) => { this.http.get(schemaFile) .toPromise() .then(fileContents => fileContents.json()) ...