Can someone provide guidance on effectively implementing this JavaScript (TypeScript) Tree Recursion function?

I'm currently grappling with coding a recursive function, specifically one that involves "Tree Recursion". I could really use some guidance to steer me in the right direction.

To better explain my dilemma, let's consider a basic example showcasing the data and my objective. Please note that the actual data is significantly more complex...

Essentially, I begin with an array containing a single array of objects as shown below, where the prop2 in any object can either be a valid string or an empty string...

[
    [
        { prop1: "abc", prop2: "" },
        { prop1: "def", prop2: "one" },
        { prop1: "ghi", prop2: "" }
    ]
]

The task at hand for my algorithm is to examine the above array, iterate over the objects, and once it encounters an object with an empty string in prop2, it must duplicate the array three times. Subsequently, it should replace the empty string in only that specific object with three different values (one/two/three) like so...

[
    [
        { prop1: "abc", prop2: "one" },
        { prop1: "def", prop2: "one" },
        { prop1: "ghi", prop2: "" }
    ],
    [
        { prop1: "abc", prop2: "two" },
        { prop1: "def", prop2: "one" },
        { prop1: "ghi", prop2: "" }
    ],
    [
        { prop1: "abc", prop2: "three" },
        { prop1: "def", prop2: "one" },
        { prop1: "ghi", prop2: "" }
    ]
]

Following this modification, the algorithm restarts afresh with the new array consisting of three arrays.

During the subsequent iteration, each of the three arrays will be replicated thrice and the empty string will undergo a similar replacement process.

In this simple instance, the end outcome would be an array comprising nine arrays.

If the original array contained more objects with empty prop2 values, additional iterations would be necessary.

Fundamentally, I am transforming an array of objects with certain props being empty strings by broadly "expanding" those particular prop values to encompass every possible permutation of "one"/"two"/"three".

Although recursion seems ideally suited for this problem, I am encountering challenges when trying to formulate the code.

It appears that the "base case" would entail having an array of objects wherein none possess properties with empty strings – returning said array in such scenarios.

However, I am uncertain about how the other case should be structured beyond invoking the same function thrice with the newly generated variants. The desired output for this alternate scenario also remains unclear to me.

Unfortunately, I have not been able to locate relevant examples resembling the task at hand online.

EDIT: Upon reviewing the responses suggesting recursive solutions, while they indeed function accurately, it is now apparent that arriving at a recursive solution has proven far from straightforward. Surprisingly, the non-recursive approach emerges as the most effective solution.

Answer №1

Here is a unique solution that can help meet your desired outcome:

const myTree = [
    [
        { prop1: "abc", prop2: "" },
        { prop1: "def", prop2: "one" },
        { prop1: "ghi", prop2: "" }
    ]
];

let nodesWithEmptyStrings = myTree.filter(n=> !!n.find(l=> l.prop2===""));
while(nodesWithEmptyStrings.length > 0) {
  nodesWithEmptyStrings.forEach(n => {
    const firstEmptyStringLeaveIndex = n.findIndex(l=> l.prop2==="");
    n[firstEmptyStringLeaveIndex].prop2 = "one";
    const copy1 = JSON.parse(JSON.stringify(n));
    copy1[firstEmptyStringLeaveIndex].prop2 = "two";
    myTree.push(copy1);
    
    const copy2 = JSON.parse(JSON.stringify(n));
    copy2[firstEmptyStringLeaveIndex].prop2 = "three";
    myTree.push(copy2);
  });
  nodesWithEmptyStrings = myTree.filter(n=> !!n.find(l=> l.prop2===""));
}

document.getElementById('result').innerText = JSON.stringify(myTree, null, 2);
<pre id="result"></pre>

Answer №2

Indeed, recursion is the key to achieving this task. The fundamental concept is to update the array and then inspect if further modifications are necessary; if so, recursively call the function with the updated array.

Below is a practical example:

const fillers = ['one', 'two', 'three'];
const propToCheck = 'prop2';

function modifyArray(arr) {
  const modified = arr.reduce((a, c) => {
    const found = c.find(v => !v[propToCheck]);
    if (found) {
      const tmp = c.filter(v => v !== found);
      return [...a, ...fillers.map(filler => [...tmp, { ...found, [propToCheck]: filler }])];
    }
    return [...a, c];
  }, []);
  const notDone = modified.some(v => v.some(o => !o[propToCheck]))
  if (notDone) {
    return modifyArray(modified);
  }
  return modified;
}

const result = modifyArray([
    [
        { prop1: "abc", prop2: "" },
        { prop1: "def", prop2: "one" },
        { prop1: "ghi", prop2: "" }
    ]
]);

console.log(result);

Answer №3

When faced with a problem that may not be naturally approached using recursion, an alternative solution involving a general function can prove effective. This particular function accepts substitutions and a key for identifying empty strings as arguments, leveraging ES6+ syntax and destructuring.

const substitute = (data, index, keyToCheck, substitutes) => {
  const indexOfObjectWithEmptyKeyToCheck = data[index].findIndex(obj => obj[keyToCheck] === "")
    if(indexOfObjectWithEmptyKeyToCheck === -1) {
        if(index === data.length - 1)
            return data
        else
            return substitute(data, index + 1, keyToCheck, substitutes)
    }
    else {
        return substitute(
            [
                ...data.slice(0, index),
                ...(substitutes.map(
                    substitute => [
                        ...data[index].slice(0, indexOfObjectWithEmptyKeyToCheck),
                        { ...data[index][indexOfObjectWithEmptyKeyToCheck], [keyToCheck]: substitute },
                        ...data[index].slice(indexOfObjectWithEmptyKeyToCheck + 1)
                    ]
                )),
                ...data.slice(index + 1)
            ],
            index,
            keyToCheck,
            substitutes
        )
    }
}


const SUBSTITUTES = ["one", "two", "three"];

const result = substitute(
    [
        [
            { prop1: "abc", prop2: "" },
            { prop1: "def", prop2: "one" },
            { prop1: "ghi", prop2: "" }
        ]
    ],
    0, 
    "prop2", 
    SUBSTITUTES
)
console.log(result)
console.log("Size of result: " + result.length)

The approach involves iterating through the array, adjusting the index only when an object with the specified key as an empty string is found. When necessary, replacements are made, and the function recurses on the same index. The termination condition occurs when the key to check is not an empty string and the current index is the last one in the input array.

I'll leave the TypeScript implementation up to you as it's more about typing the input data rather than solving the primary issue at hand.

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

When utilizing a custom hook that incorporates useContext, the updater function may fail to update as

After developing a customized react hook using useContext and useState, I encountered an issue where the state was not updating when calling the useState function within the consumer: import { createContext, ReactNode, useContext, useState, Dispatch, SetSt ...

Different types of AES256 variants

Currently, I am developing an Electron desktop application and planning to store data in a JSON file that needs to be encrypted and decrypted for security reasons. This data will be accessed and modified by the application periodically. After some researc ...

ways to incorporate searching within JSON data using AJAX and jQuery in JavaScript

My search box needs to have JSON data appended into it. Below is the HTML code: <input type="search" id="merchantName" name="merchant" placeholder="enter merchant name"></input> I have JSON data containing merchant names that I want to appen ...

What is the best way to iterate through only the selected checkboxes to calculate their

I am in need of calculating the selected checkboxes only within a table field (harga_obat*jumlah) Below is my foreach data: @foreach ($obat as $o) <tr> <td> <input id="check" type="checkbox" name="select[]" value="{{ $o->nam ...

Integrating dynamic transition effects using Jquery Mobile for <div> elements

Just a friendly reminder, I must admit that my knowledge of Javascript is quite limited. I received a script from Padilicious to implement swipe navigation on my Jquery Mobile Site. It involves adding functions to a div tag like this: <div data-ro ...

Transforming an HTML file into a Vue.js component

I'm working on a login.vue file and I need to incorporate styling along with the necessary js and css files. Unfortunately, I'm clueless about how to achieve this within the login.vue file. Below is a snippet from the html file: <!DOCTYPE ht ...

A long error occurred while using the payloadaction feature of the Redux Toolkit

import { createSlice, PayloadAction, createAsyncThunk } from "@reduxjs/toolkit" import axios, { AxiosError} from "axios" type user = { id: number, token: string } export type error = { error: string } interface authState { user: user | ...

Add the specified HTML tag to the existing document. An error has occurred: HierarchyRequestError - The action would result in an invalid node

During my testing of a React/TypeScript project using Jest + Enzyme, I encountered an issue when trying to append an HTML tag. The error occurred with the following unit test code: const htmlTag: HTMLElement = document.createElement('html'); htm ...

`Animate your divs with slide in and slide out effects using

Currently, I am in the process of replicating a website and facing some challenges. This site is my inspiration for the project. I have managed to create a sliding effect using CSS, making the div slide in and out from the same direction. However, I want ...

Execute operations on element itself rather than the output of document.getElementbyId

I encountered an issue involving an HTML element with the ID of BaseGridView. When I call a function directly on this element, everything works perfectly. However, if I use document.getElementById() to retrieve the element and then call the function, it do ...

Updating a Nested Form to Modify an Object

There is an API that fetches an object with the following structure: { "objectAttributes": [ { "id": "1", "Name": "First", "Comment": "First" }, { "id": "2", "Name": "Second", "Comment": "Second" } ] ...

Preserve the wpColorPicker selection using personalized knockout bindings

Utilizing wpColorPicker and knockout, my goal is to update the color picker value in my observable and then store it in the database as JSON. While other elements successfully update and save, there seems to be an issue with my custom binding for the data ...

Tips for simulating a Ref

I have a Vue3 component where, within the setup(), I have defined the following function: const writeNote(note: Ref<Note>) => { console.log(`note ${note.id}`) } This function takes a Ref<Note>, with Note being an Interface. There are two s ...

Struggling to make comparisons with numerical data from MongoDB in an ExpressJS route

I am currently developing a website using Node.js, EJS template, MongoDB, and Express. I am working on implementing search functionality on my page using forms, but I am encountering a small issue. The problem is related to a logical issue in the search f ...

Guide on incorporating JSON information into an HTML table

Currently, I am retrieving data that needs to be added to an HTML table once it is received. I have attempted some methods, but I am unable to dynamically add the data after the page has loaded. I aim to accomplish this using either JavaScript or jQuery. ...

Each time the button is clicked, the settings and values will rotate, creating a new

I'm looking to create a button system that transitions from "unmarked" to "form" and updates the database with each click. I want users to be able to cycle through the buttons, triggering a post request via ajax to update the associated ID in the data ...

Extract specific index from a JSON array

I'm a beginner in Jquery and javascript, I am using ajax to upload an image and trying to fetch the image url. However, I keep encountering errors every time I try. Can someone assist me with this? Thank you! Here is the error message I received: Un ...

Can we enhance the efficiency of this equation?

The formula provided organizes the elements in the container based on mouse movement. The issue stemmed from the image size and the different calculations performed when approaching along the x and y axes from various directions. const zoomEffect = (even ...

Unable to group the array based on the key value using Jquery or Javascript

I am looking to group my array values based on specific key values using Jquery/Javascript, but I am facing issues with my current code. Let me explain the code below. var dataArr=[ { "login_id":"9937229853", "alloc ...

Using Vue.js for instant field validation when sending PHP post forms for enhanced user experience

A unique approach is being taken to utilize vue.js exclusively for real-time field validation, while the form will ultimately be submitted using PHP through the POST method. However, a challenge arises where vue.js takes control of the form, hindering PHP& ...