JavaScript - Generate a hierarchical object structure from an array by considering specific boundary conditions

Dealing with recursion is always a challenge.

In my current project, I'm working with the following array:

fooArray: Foo[] = 
[
  { foo: "a", indent: 0 },
  { foo: "b", indent: 1 },
  { foo: "c", indent: 2 },
  { foo: "d", indent: 1 },
  { foo: "e", indent: 2 },
  { foo: "f", indent: 2 },
  { foo: "g", indent: 1 },
  { foo: "h", indent: 0 },
]

My goal is to transform this into a different object type in TypeScript and arrange them in a nested structure based on their indent values like this:

interface Bar {
  foo: string,
  bar?: Bar[]
}

barArray: Bar[] = 
[
  { 
    foo: "a", 
    bar: [
      { foo: "b",
        bar: [{ foo: "c" }],
      { foo: "d",
        bar: [
          { foo: "e" }, 
          { foo: "f"}
        ] 
      },
      {
        foo: "g"
      }
    ]
  },
  { foo: "h" }
]

I've been experimenting with reducers to achieve this transformation, but determining how deep the recursion should go based on neighboring elements in the array is really challenging. Any insights or suggestions on this matter would be greatly appreciated!

Answer №1

My process is still a work in progress, so it's not ready for testing yet. I'm taking a break but leaving my code here to revisit later:

let fooArray = [
  { foo: "a", indent: 0 },
  { foo: "b", indent: 1 },
  { foo: "c", indent: 2 },
  { foo: "d", indent: 1 },
  { foo: "e", indent: 2 },
  { foo: "e1", indent: 1 },
  { foo: "e2", indent: 0 },
  { foo: "e3", indent: 1 },
  { foo: "f", indent: 2 },
  { foo: "g", indent: 1 },
  { foo: "h", indent: 0 },
];

// let barArray = fooArray.slice().flatMap((e,i,a) => i ? null : Array(a.filter(f => !f.indent).length).fill().map((f,j,b) => a.splice(0,Math.max(a.slice(1).findIndex(g => g.indent === 0)+1,1))));

// WIP // let barArray = fooArray.slice().flatMap((e,i,a) => i ? null : Array(a.filter(f => !f.indent).length).fill().map((f,j,b) => a.splice(0,Math.max(a.slice(1).findIndex(g => g.indent === 0)+1,1)))).map(e => e.map((f,i,a) => a[i+1]?.indent > f.indent ? { foo: f.foo, bar: a.splice(i+1,i+2) } : f).filter(f => f));

// WIP #2 // let barArray = fooArray.slice().map(e=>({...e})).flatMap((e,i,a) => i ? null : Array(a.filter(f => !f.indent).length).fill().map((f,j,b) => a.splice(0,Math.max(a.slice(1).findIndex(g => g.indent === 0)+1,1)))).map(e => e.reverse().map((f,i,a) => /*console.log(`a[i]: ${JSON.stringify(a[i])}\nf: ${JSON.stringify(f)}`) ||*/ a[i+1]?.indent < f.indent ? (a[i+1].bar = [{foo:f.foo}], a.splice(i,i+1)) : {foo:f.foo}).filter(f=>f).reverse());

// WIP #3 // let barArray = fooArray.slice().map(e=>({...e})).flatMap((_,i,a) => i ? null : Array(a.filter(e => !e.indent).length).fill().map(e => a.splice(0,Math.max(a.slice(1).findIndex(f => f.indent === 0)+1,1)))).map(e => e.length > 1 ? e.flatMap((_,i) => i ? null : Array(e.filter(e => !e.indent).length).fill().map(f => e.splice(0,Math.max(e.slice(1).findIndex(g => g.indent === 0)+1,1)))) : e);

// simple get object // let barArray = fooArray.slice().map(e=>({...e})).flatMap((_,i,a) => i ? null : Array(a.filter(e => !e.indent).length).fill().map(e => a.splice(0,Math.max(a.slice(1).findIndex(f => f.indent === 0)+1,1)));

// NEW WIP

fooArray.slice().map(e=>({...e})).flatMap((_,i,a) => i ? null : Array(a.filter(e => !e.indent).length).fill().map(e => a.splice(0,Math.max(a.slice(1).findIndex(f => f.indent === 0)+1,1)))).map(e => e.length > 1 ? { foo: e[0].foo, bar: e.slice(1) } : e[0])
.map(a => a.bar ? 
    ((a.bar = a.bar.reverse().flatMap((e,i) => 
        a.bar.findIndex((f,j) => j > i && e.indent !== f.indent) !== -1 ? 
            (a.bar.find((f,j) => j > i && e.indent !== f.indent).indent > e.indent ? e : (a.bar.find((f,j) => j > i && e.indent !== f.indent).bar = a.bar.splice(i,a.bar.findIndex((f,j) => j > i && e.indent !== f.indent))))
            : e
    ).reverse()), a)
    : a
)

console.log(barArray);

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

invoke a fresh PHP page and transmit a lengthy string of text

I have a PHP page named 'main' and would like to trigger another PHP page called 'printpage' when the user clicks the mouse. I need to transfer a large amount of text in this process. Instead of passing the text as a URL parameter, whi ...

Having trouble with AJAX not functioning properly while waiting for an asynchronous call

After using deferred to wait for two functions to complete before feeding a select in the template, I encountered an issue where the assignLocationToSelector function did not seem to run as expected. When a tab is displayed, I do the following: var notAs ...

Issue encountered while adding an element to a numpy array in Python

I am trying to assign values to a 3D array that I have defined and initialized, but for some reason, the assignment is not working. Can anyone help me understand why? Thank you. import numpy as np xy = np.array([[(0,0) for _ in np.arange(0,2,0.5)] for _ i ...

What is the method for including the value of a missing object once it has been compared to another array

My task involves dealing with an array of months (var months). I want to filter out the months that are missing in another array of objects (var array1) and add a property Avg with a value of 0 for those missing months. var months = ["Jan", " ...

connecting a JavaScript object literal to a specific address within an HTML document

I'm encountering an issue with creating an object that contains properties such as {"name":"John Doe","email":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e08e818d85a0848f8d81889c8b848d8a">[email protected]</ ...

Generating a JSON Object by combining elements from multiple arrays

I need assistance in creating a single Json object from two arrays using JavaScript or jQuery. The data is stored in the database in the format shown below: clob_field_1: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 etc etc ... clob_field_2: 8106.23, 7856.49, 8009.15, ...

Angular - Incorporating Query Parameters into URL

For instance, let's say I have the following URL: http://local.com/. When I invoke the function in my SearchController, I aim to set text=searchtext and generate a URL like this: http://local.com/?text=searchtext. Is there a way to achieve this? I at ...

Angular 2 can efficiently generate multiple HTTP requests simultaneously from a single HTTP request

Backend API's: url: [ { "name": "ABC", "occupation": "Student", "address_url": "http://www.sample.com/address/person=hgjgjgyyfhg" }, { "name": "ABC1", "occupation": "Carpenter", "address ...

Saving two separate arrays in local storage using JavaScript

Let's say I have two arrays: myFavCars and myDislikedCars. How can I combine them and store in local storage like this: localStorage.setItem('myPreferences', { myFavCars: [], myDislikedCars: [] }) Is it feasible to store two separate arrays ...

ClickEvent (or element selector) is experiencing functionality issues

I'm currently working on creating a small calculator using HTML, CSS, and JS. However, I'm facing an issue with selecting buttons of the calculator from the HTML script and adding EventListeners to them. Here is a snippet of my HTML code: `< ...

Retrieve image files from the static directory and showcase them in the client application

Currently, I am storing images in a static folder within my Express server app and everything is functioning as expected. The crucial code snippet responsible for this operation is shown below: app.use('/uploads', express.static(Path.join(__dirn ...

Tips for eliminating null elements from an array with the help of jquery

Similar Question: How to delete empty values from an array using JavaScript? I'm looking for a way to eliminate null or empty elements from an array with the use of jquery var clientName= new Array(); clientName[0] = "jack"; clientName[1] = ""; ...

Set up an event listener for when geolocation permission is approved

My Setup: I've written some basic code snippet below: const onSuccess = () => { console.log('success'); } const onError = () => { console.log('error'); } navigator.geolocation.getCurrentPosition(onSuccess, onError) ...

Extracting video frames in three.js for future reference

Currently, I am utilizing three.js version r73 and have implemented a fragment shader that showcases video frames with code like this: gl_FragColor = texture2D( iChannel0, uv); My objective is to introduce another uniform (let's call it iChanne ...

The toast added to the DOM is not displaying when using the show() function

I'm experimenting with utilizing Bootstrap 5's toast component to exhibit response messages following a jquery Ajax call. For the successful part, I conclude with this code snippet: itsToastTime(response.status, response.message) let toast = $( ...

Having trouble with D3.js Tooltip not showing up when mousing over elements?

I am working on a project involving a map of Kansas City that includes data on the number of crimes in each neighborhood. My goal is to add a tooltip that displays this crime data when hovering over each district. Here is how I have set it up so far: var ...

Having trouble retrieving my static files in express.js - running into conflicts

Hey there! I'm currently working on creating a webapp for purchasing tickets using express.js. I've encountered an issue with loading static files onto a specific page that directs users to information about a party. It seems like express.js is u ...

Using jQuery to create a click function that determines the length and pattern of an input

I've been grappling with a problem for the past two days. I have a webpage that prompts users to enter their phone number, and I'm attempting to create a "validator" for the phone number input field. However, I'm struggling to determine how ...

Experience the power of React 16 and Babel 6 directly in your web browser

Looking to utilize React directly in the browser without the need for bundles using browserify/webpack. Experimenting with babel-standalone and react from the browser, encountering a 'ReactDOM is not defined' error along with two other warnings ...

When utilizing the split method, the initial element within the array of strings will be blank

Currently, I am facing an issue where I need to read numbers from a file and store them in an array. I have come across discussions about whitespace causing problems, so I decided to use the trim method. Here is what I have done: String[] tokens = new Str ...