Delete items from the array based on the relationship between them

Looking for a way to remove elements in an array based on their relationships with each other?

For example:

  const array = [
    {
      id: 14098,
      parent: 14096,
    },
    {
      id: 14100,
      parent: 0,
    },
    {
      id: 14096,
      parent: 14100,
    },
  ];

The task at hand involves iterating through the array and deleting the parent element. In doing so, all child elements associated with that parent should also be removed... and even child elements of those child elements.

Any suggestions on how to approach this?

Best regards,

Ricardo

Answer №1

Even though Stack Overflow isn't a platform for receiving free coding solutions, I found this problem intriguing and decided to take a shot at it. The approach I took was to identify all the elements that need to be removed first before actually removing them.

let array = [{
    id: 14098,
    parent: 14096,
  },
  {
    id: 14100,
    parent: 0,
  },
  {
    id: 14096,
    parent: 14100,
  },
  {
    id: 14097,
    parent: 14000,
  },
  {
    id: 15098,
    parent: 14098,
  },
  {
    id: 3,
    parent: 0,
  },
];



function getNewArrayWithRemovedIds(origArray, removeid) {
  let removearray = [removeid]
  const cb = (e) => (e.parent == removeid && removearray.push(e.id))
  let x = array
  while (x.length > 0) {
    x = origArray.filter(el => cb(el))
    if (x.length > 0) removeid = x[0].id
  }
  return origArray.filter(el => removearray.indexOf(el.id) == -1);
}
console.log(getNewArrayWithRemovedIds(array, 14100))

Answer №2

Here is the proposed approach:

function cleanArray(array, element) {
    let prevSize = -1;
    let currentSize = array.length;
    let blacklist = [element];
    while (prevSize != currentSize) {
        prevSize = currentSize;
        array = array.filter((item) => {
            if ((blacklist.indexOf(item.parent) >= 0) || (blacklist.indexOf(item.element) >= 0)) blacklist.push(item.element);
            else return true;
        });
        currentSize = array.length;
    }
    return array;
}
  const data = [
    {
      element: 14098,
      parent: 14096,
    },
    {
      element: 14100,
      parent: 0,
    },
    {
      element: 14096,
      parent: 14100,
    },
    {
      element: 5,
      parent: 6
    }
  ];
  
  console.log(cleanArray(data, 14100));

In this method, we keep adding new items to a list until no more are found.

Answer №3

An example to demonstrate the concept:

const data = [
  { id: 14098, parent: 14096 },
  { id: 14099, parent: 14096 },
  { id: 14100, parent: 0 },
  { id: 14096, parent: 14100 },
  { id: 14200, parent: 0 },
  { id: 14210, parent: 14200 },
];

const delete_item_by_id = (array, id) => {
  const index = array.findIndex((item) => item.id === id);
  if(index > -1) array.splice(index, 1);
};

const delete_item_and_children = (array, id) => {
  let queue = [id];
  delete_item_by_id(array, id);
  
  while(queue.length > 0) {
    let current = queue.pop();
    queue.push(...array.filter((item) => item.parent === current).map((item) => item.id));
    delete_item_by_id(array, current);
  }
};

delete_item_and_children(data, 14100);

console.log(data);

If dealing with a large array, consider using a map for efficient child item retrieval, avoiding costly filter calls.

If possible, share your progress so far for better guidance from others.

Modified version utilizing a map approach (without altering original data):

const data = [
  { id: 14098, parent: 14096 },
  { id: 14099, parent: 14096 },
  { id: 14100, parent: 0 },
  { id: 14096, parent: 14100 },
  { id: 14200, parent: 0 },
  { id: 14210, parent: 14200 },
];

const get_child_map = (array) =>
   array.reduce(
    (map, { id, parent }) => {
      let arr = map.get(parent);
      if(!arr) map.set(parent, arr = []);
      arr.push(id);
      return map;
    },
    new Map()
  );

const filter_out_item_and_descendents = (array, delete_id) => {
  const child_map = get_child_map(array);
  
  let remove = new Set([delete_id]);
  let queue = [delete_id];
  
  while(queue.length > 0) {
    let current = queue.pop();
    queue.push(...(child_map.get(current) ?? []));
    remove.add(current);
  }
  
  return array.filter(({ id }) => !remove.has(id));
};

console.log(filter_out_item_and_descendents(data, 14100));

Answer №4

After reviewing the existing answers, I have come up with a revised approach to solving this problem that addresses the issues pointed out by Ben Stephens:

const getDescendantIds = (items, target) => {
  const elements = items.filter(({parent}) => parent == target);
  return [target].concat(elements.flatMap(el => getDescendantIds(items, el.id)));
}

const removeSubTree = (items, target, ids = getDescendantIds(items, target)) =>
  items.filter(({id}) => !ids.includes(id));

const array = [{id: 14098, parent: 14096}, {id: 14100, parent: 0}, {id: 14096, parent: 14100}];

console.log('removing 14096', removeSubTree(array, 14096));
console.log('removing 14098', removeSubTree(array, 14098));
console.log('removing 14100', removeSubTree(array, 14100));
.as-console-wrapper {max-height: 100% !important; top: 0}

This solution breaks down the problem into two steps. First, we recursively retrieve the ids of the nodes descending from the one with our target id. Then, we filter the list to create a new list without those ids.

It's important to note that this method returns a copy of the original list without the specified values. The original list remains untouched as we do not mutate it. We strive for civilized coding practices!

Revised Approach

The initial code had errors, which were corrected based on feedback from Ben Stephens. The use of filter instead of find was crucial for proper execution.

const getDescendantIds = (items, target) => {
  const element = items.find(({parent}) => parent == target);
  return [target].concat(element ? getDescendantIds(items, element.id) : []);
}

const removeSubTree = (items, target, ids = getDescendantIds(items, target)) =>
  items.filter(({id}) => !ids.includes(id));

const array = [{id: 14098, parent: 14096}, {id: 14100, parent: 0}, {id: 14096, parent: 14100}];

console.log('removing 14096', removeSubTree(array, 14096));
console.log('removing 14098', removeSubTree(array, 14098));
console.log('removing 14100', removeSubTree(array, 14100));
.as-console-wrapper {max-height: 100% !important; top: 0}

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

React application not displaying element properly?

I am facing an issue with my react modal that displays a sign-in and sign-up form. The problem arises when I try to access the button on the form using its id, which is modal-sign-in-submit-button. document.getElementById('modal-sign-in-submit-button ...

It appears that combining Object.assign with Function.prototype may not function as expected

Currently attempting to develop a mixin for a sophisticated feature within a library. My initial approach was successful: const proto = Object.create(Function.prototype); However, I now face the challenge of implementing multiple inheritance where an ob ...

Retrieving the selected value and inserting the ID instead of the string into the database in PHP using the MVC design pattern

Hello there, I'm encountering a challenge with my registration form. The user inputs their username, email password, and selects a value from a dropdown menu. When the user submits the form, instead of sending the option selected as a string, it shoul ...

Managing an iframes website using buttons and links: Tips and tricks

I am trying to create a website that includes an iframe for navigating through external websites using previous and next buttons. I also want to display the links on a sidebar so that users can click on them to automatically load the site in the iframe. I ...

Unable to extract all advertisements from Facebook Marketplace

https://i.stack.imgur.com/xEhsS.jpg I'm currently attempting to scrape listings from Facebook marketplace, however, only the first listing is being scraped. Does anyone have any suggestions on how I can scrape the entire list of listings? CODE (async ...

The React function was misusing the useEffect hook, causing it to be

I seem to be encountering a problem when trying to call useEffect within this function. As someone who is relatively new to React, I may have made some noticeable mistakes, but dealing with this issue is becoming quite time-consuming. The function in ques ...

Is there a way to adjust the time font size according to the dimensions of the time picker?

HTML and CSS .pickthetime { height: calc(var(--vh, 1vh) * 3); width: calc(var(--vw, 1vw) * 25); align-content: center; // center looks better, also tried left to stop it from breaking a new line on Safari on iOS font-weight: 300; } <input cla ...

Having issues with the basic KnockoutJS binding not functioning as expected

There appears to be an issue with my KnockoutJS script that I'm struggling to pinpoint. Below is the snippet of HTML code: <h2>SendMessage</h2> <div class="form-group" id="messageSender"> <label>Select User Type</l ...

Implementing jQuery's live() method to handle the image onload event: a guide

Looking to execute a piece of code once an image has finished loading? Want to achieve this in a non-intrusive manner, without inline scripting? Specifically interested in using jQuery's live() function for dynamically loaded images. I've attemp ...

Securing ASP.NET Web API with Cross-Domain AJAX Requests: A Comprehensive Guide

I am in the process of developing an API on www.MyDomain.com that needs to be accessible from public websites such as www.Customer1.com and www.Customer2.com. These websites are designed to showcase each customer's inventory without requiring users to ...

The search functionality in an Html table is currently malfunctioning

Currently, I am working on developing a search mechanism in HTML. It seems to be functioning properly when searching for data for the first time. However, subsequent searches do not yield the expected results. Additionally, when trying to search with empty ...

checkbox revision

I'm attempting to update some text indicating whether or not a checkbox is checked. The issue is that when the checkbox is checked, the textbox disappears and the text takes its place. <form name="myForm" id="myForm"> <input type="checkb ...

The efficiency of the Angular app in production is hindered by a file that takes a whopping 5 seconds to load

After successfully compiling my project for production using the command ng build --prod, I made sure to implement certain production settings in angular.json: "production": { "fileReplacements": [ { "replace": "src/environments/e ...

Is it possible to display events on fullcalendar.io using PHP and MySQL?

I'm currently trying to integrate a calendar feature on my website using PHP's "while" command. I don't have knowledge of JSON or AJAX, so I'm unsure if those are viable options for me. The issue I'm facing is that the current code ...

Unable to retrieve unique array names from JSON document

I have various JSON files similar to the following structure. { "09800214851900C3": { "label": "P7-R1-R16:S2", "name": "Geist Upgradable rPDU", "state": "normal", "order": 0, "type": "i03", "snmpInstance": 1, "lifetimeEnergy" ...

Organize the jumbled array

Within the application, there exists an array known as newArray which contains numerous numbers. These numbers are transmitted to a server and stored in a separate array called stalkers. The issue arises when certain names are returned faster than others, ...

AngularJS xeditable: sending updated data to the server

I am currently utilizing AngularJS to display products in a table for my users. Users have the ability to filter the table using categories or keywords. However, they should also be able to edit the product information within the table, such as product nam ...

Is it necessary to use callbacks when using mongoose's findbyid with express to retrieve an object from the database? Are callbacks still important in modern JavaScript frameworks?

I'm currently exploring the express local library tutorial on MDN docs and wanted to try out returning an object without relying on a callback method. When I provide the request object parameter for the id to the findById mongoose method like this va ...

How can I activate a jQuery function only when it is within the viewport?

I have installed a jQuery Counter on my website, but I am experiencing an issue where the counter starts or finishes before reaching the section where the HTML code is embedded. Any assistance with this problem would be greatly appreciated! <script& ...

Creating dynamic elements in JavaScript utilizing Bootstrap cards

Looking for help in integrating Bootstrap cards while dynamically generating elements using JavaScript? I am working on a project where I need to generate a list of restaurant recommendations based on user preferences entered through a form, utilizing the ...