Tips for organizing two arrays into a nested array using objects

Transforming two flat arrays with objects into a nested array is the objective. When an id from list B matches a refId in list A, the object gets appended as a child to the object in list A. This operation results in a new array structured with 2 levels deep, as exemplified.

In List B, there exist objects having ids that correspond to refIds of their sibling objects. In such instances, the code should identify these matches and add them as children of children of the parent object. Consequently, this nesting extends up to 3 levels deep. The nesting process should persist until all possible matches are exhausted.

Is there a modification for the below code to handle nesting at any number of levels, based on matching ids and refIds?

// TOP LEVEL
const listA = [ 
  { 
    "id": 23,
    "refId": 23, 
    "name": 'list A #1',
    "isNested": false,
    "depth": 1,
    "children": []
  }, 
  { 
    "id": 25,
    "refId": 25, 
    "name": 'list A #1',
    "isNested": false,
    "depth": 1,
    "children": []
  }
]
// NO HEIRARCHY
const listB = [ 
  { 
    "id": 23,
    "refId": 1234,
    "name": "test 1",
    "isNested": true, 
    "depth": 2, 
    "children": []
  },
  { 
    "id": 25,
    "refId": 1212,
    "name": "test 1",
    "isNested": true, 
    "depth": 2, 
    "children": []
  },
  { 
    "id": 1234,
    "refId": 4324,
    "depth": 3,
    "name": "test 2",
    "isNested": true, 
    "children": []
  }, 
  { 
    "id": 1234,
    "refId": 5678,
    "depth": 3,
    "name": "test 3",
    "isNested": true, 
    "children": []
  }
]

const nestedArr = listA.map(
  ({ id, name, refId, children }) => {
    return {
      id,
      name,
      refId,
      children: listB.filter((b) => {
        return b.id == refId ? b : ''
      }),
    }
  }
)

console.log(nestedArr)

Answer №1

If you have correctly ordered refs, you can follow these steps:

  • Combine both arrays
  • For each element,
    • Save the ref in a Map for easy access later on
    • If id === refId, add it as a top level ref
    • If not, find its parent and add it to the children array
const refs = new Map();
const nestedArr = [];

for (const ref of listA.concat(listB)) {
  refs.set(ref.refId, ref);
  
  if (ref.id !== ref.refId) {
    refs.get(ref.id).children.push(ref);
  } else {
    nestedArr.push(ref);
  }
}

console.log(nestedArr)

Try running this code snippet:

// TOP LEVEL
const listA = [ 
  { 
    "id": 23,
    "refId": 23, 
    "name": 'list A #1',
    "isNested": false,
    "depth": 1,
    "children": []
  }, 
  { 
    "id": 25,
    "refId": 25, 
    "name": 'list A #1',
    "isNested": false,
    "depth": 1,
    "children": []
  }
]
// NO HIERARCHY
const listB = [ 
  { 
    "id": 23,
    "refId": 1234,
    "name": "test 1",
    "isNested": true, 
    "depth": 2, 
    "children": []
  },
  { 
    "id": 25,
    "refId": 1212,
    "name": "test 1",
    "isNested": true, 
    "depth": 2, 
    "children": []
  },
  { 
    "id": 1234,
    "refId": 4324,
    "depth": 3,
    "name": "test 2",
    "isNested": true, 
    "children": []
  }, 
  { 
    "id": 1234,
    "refId": 5678,
    "depth": 3,
    "name": "test 3",
    "isNested": true, 
    "children": []
  }
];

const refs = new Map();
const nestedArr = [];

for (const ref of listA.concat(listB)) {
  refs.set(ref.refId, ref);
  
  if (ref.id !== ref.refId) {
    refs.get(ref.id).children.push(ref);
  } else {
    nestedArr.push(ref);
  }
}

console.log(nestedArr)

Note: this will modify the original elements

Answer №2

To efficiently link the node objects with their corresponding refId, you can utilize a Map structure created using the constructor function. Then, by iterating through the second list, you can establish the necessary connections.

It's important to note that this approach alters the existing arrays within the children property of listA, resulting in the following outcome:

const listA = [{"id": 23,"refId": 23,"name": 'list A #1',"isNested": false,"depth": 1,"children": []},{"id": 25,"refId": 25,"name": 'list A #1',"isNested": false,"depth": 1,"children": []}];
const listB = [{"id": 23,"refId": 1234,"name": "test 1","isNested": true,"depth": 2,"children": []},{"id": 25,"refId": 1212,"name": "test 1","isNested": true,"depth": 2,"children": []},{"id": 1234,"refId": 4324,"depth": 3,"name": "test 2","isNested": true,"children": []},{"id": 1234,"refId": 5678,"depth": 3,"name": "test 3","isNested": true,"children": []}];

const map = new Map(listA.concat(listB).map(node => [node.refId, node]));
for (const {id, refId} of listB) map.get(id).children.push(map.get(refId));

console.log(listA);

If preserving the original data is essential, ensure to create fresh arrays for the children property:

const listA = [{"id": 23,"refId": 23,"name": 'list A #1',"isNested": false,"depth": 1,"children": []},{"id": 25,"refId": 25,"name": 'list A #1',"isNested": false,"depth": 1,"children": []}];
const listB = [{"id": 23,"refId": 1234,"name": "test 1","isNested": true,"depth": 2,"children": []},{"id": 25,"refId": 1212,"name": "test 1","isNested": true,"depth": 2,"children": []},{"id": 1234,"refId": 4324,"depth": 3,"name": "test 2","isNested": true,"children": []},{"id": 1234,"refId": 5678,"depth": 3,"name": "test 3","isNested": true,"children": []}];

const map = new Map(listA.concat(listB).map(node => [node.refId, {...node, children:[]}]));
for (const {id, refId} of listB) map.get(id).children.push(map.get(refId));

const nestedListA = listA.map(({id}) => map.get(id));
console.log(nestedListA);

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

Determining the aspect ratio of an image

When trying to append an image to a div, I use the following code segment: $thisComp.find('.DummyImage').attr("src", this.imageUrl); Following this, I make an ajax call to retrieve the aspect ratio of the image: $.ajax(this.imageUrl).done( ...

When using Node.js with Express and ssh2, my data structures remain intact without any resets when loading web pages

To display jobs sent by users to a cluster, the code below is used (simplified): var split = require('split'); var Client = require('ssh2').Client; var conn = new Client(); var globalRes; var table = [["Head_1","Head_2"]]; module.exp ...

How do I convert the object value/data to lowercase in JavaScript using underscore for an HTML5 document?

I am working with an array of objects (arr) where each object consists of 3 properties (Department, Categories, ProductTypes). The values for these properties are a mix of upper and lower case. To perform a comparison between arr and a search filter (alrea ...

Challenges in utilizing Jquery Ajax

I'm currently facing an issue with implementing ajax using jquery. I am trying to load text from a file using ajax in combination with asp.net, but when I load a file, update the text content, save it onto the file, and then try to load the file again ...

What is the best method for storing a client-side token in nextjs 13 with the App Router update?

We are currently using a nextjs 13.5 web application. The new app router paradigm in Next.js 13 involves all components, including client components, going through their initial render on the server during a full page load (such as after a refresh). Accord ...

Array Connections

There's a bit of a dilemma I'm facing. I might be taking the long route, but honestly, I'm not sure. If you could assist me, I would greatly appreciate it. The issue at hand is that I am uploading photos to FTP and saving the URLs in MySQL ...

The value stored in $_POST['valuename'] is not being retrieved

Having recently delved into ajax, I am encountering some difficulties in making it function properly. The objective of the code is to send two variables from JavaScript to PHP and then simply echo them back as a string. However, instead of receiving the e ...

The role of arrays and pointers in the C programming language

I've always found it interesting why I can use the name of an array of characters to access the whole string in C, but I can't do the same with types like int and char* int numbers[]={26,8,1995}; char name[]="Omar"; char* full_name[]={"Omar","Kh ...

How to shuffle the elements of an array saved in a JSON file using discord.js

I've been working on a Discord bot as a way to learn more about Javascript. While creating a command that pulls random quotes from an array stored in a separate JSON file, I encountered an issue that has me stumped. var config = require("./settings.j ...

Is there a way to deactivate the <script> tag using CSS specifically for media queries?

When designing a website exclusively for desktop usage, I encountered the issue of it not being viewable on mobile devices. I attempted to address this problem by utilizing the code below: script { display: none; pointer-events: none; } Unfortunat ...

Is it possible for the req.url path in expressjs to represent a different URL?

Recently, I discovered some suspicious requests being sent to my node-express server. In response, I created a middleware to record the request URLs. After logging these requests, I noticed that most of them started with '/', but there were also ...

Locate the nearest upcoming date and time to today's date in the JSON response

I am currently working with an API that provides a response containing the `start_time` field in JSON format. My goal is to extract the ID from the JSON object whose next date time is closest to the current date and time, excluding any dates from the past. ...

What is the best way to utilize scanner input across multiple arrays simultaneously?

I am currently developing a program that deals with displaying specific values related to planets stored in multiple arrays. The input from the scanner is crucial for determining which array values should be displayed. package eindopdrachtse; import java ...

What is the best way to display text from one text field onto another text field?

Here's a challenging question that I've been pondering... Issue: I am using a virtual keyboard that needs to interact with different text fields on various pages. Every time I click on a text field, the keyboard should appear, and every key I pr ...

Guidelines for displaying JSON data in HTML <ul><li></li></ul> format using jQuery within an ASP.NET environment

I am currently developing an asp.net application that involves fetching data from a database in JSON format and displaying it within html ul-li tags using jQuery. Below is a snippet of my Html Page: <html xmlns="http://www.w3.org/1999/xhtml"> <he ...

Utilizing the Keycloak admin API to efficiently assign client roles to users by iterating through a loop

During my experimentation with the keycloak assign role to a user feature using nodejs, I encountered an issue. While I can successfully assign a role to a single user by providing the user id, client id, and role details (name,id) once, I am now looking t ...

Is there a way to combine stubbing and spying simultaneously?

Currently, I am testing a function that involves calling another function which returns a promise. The System Under Test (SUT) is structured as follows: fn($modal) -> modalInstance = $modal.open({ controller: 'myCtrl' size: ...

Struggling to implement sparklines for real-time data in the AngularJS adaptation of the SmartAdmin template

Currently, I am embarking on a project that involves utilizing the AngularJS version of the SmartAdmin Bootstrap template foundhere. Within this project scope, I am required to integrate sparklines into various pages. I have successfully implemented them ...

Is it possible for multiple queries executed within a websql transaction to be run concurrently?

An informative tutorial online demonstrates the following transaction: db.transaction(function (tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)'); tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "foobar")&ap ...

Issue with passing a placeholder as a prop in a Vue form component

One of the components in my project is the Form Answer component: <template> <div class="flex flex-col items-center justify-center gap-2"> <!-- <p class="font-semibold">{{ ansLabel }}</p> --> < ...