Guide to recursively iterating through an array of objects in TypeScript/Javascript

In my current programming challenge, I am dealing with an array of objects that have two properties: target and source. Additionally, there is a designated starting source to begin with.

The goal is to start from the starting source and recursively find a target from the given array. Once a target is found, it becomes the new source and the process continues until the target value is undefined.

I am seeking an efficient way to achieve this task and would appreciate any concise code suggestions.

let result = new Array();
// input
    const a = [
      { source: '2', target: '3' },
      { source: '1', target: '2' },
      { source: '3', target: '4' },
      { source: '4', target: '5' }
    ];
    const startSource = '1';
    result.push(startSource);
   // recursive function
    this.findTarget(startSource, a);
    console.log(result);

Here is the recursive function I have implemented:

 public findTarget(s: string, a: Sequence[]): any {
    let obj = a.find(i => i.source === s);
    if (obj) {
      this.result.push(obj.target);
      return this.findTarget(obj.target, a);
    } else {
      return;
    }
  }

Answer №1

To simplify the process, you can create a hashmap or plain object where the source is the key and the target is the value. This eliminates the need for recursion and allows for a straightforward chaining of values until completion.

By utilizing this map, you can gather all values until there are no more defined targets in the map[nextSource] sequence.

The following method accomplishes this efficiently by leveraging function generators to yield the discovered values.

This approach is considered the most efficient due to the O(1) complexity of creating the lookup table once compared to the higher complexity of applying find in every iteration (potentially O(n) or O(n^2)).

If preferred, the use of function generators can be replaced with collecting the results directly. Function generators were chosen for their simplicity and ease of maintenance.

SIDE NOTE: The provided sample code initially pushes a source followed by targets. If targeting specific data, modify yield startSourceValue; to

yield reverseMap[startSourceValue];
.

Below is the functional code snippet:

const a = [
  { source: '2', target: '3' },
  { source: '1', target: '2' },
  { source: '3', target: '4' },
  { source: '4', target: '5' }
];
const startSource = '1';

function* chainSources(array, targetKey, sourceKey, startSourceValue) {
  const reverseMap = array.reduce((acc, item) => {
    acc[item[sourceKey]] = item[targetKey];
    return acc;
  }, {});

  while (reverseMap[startSourceValue] !== undefined) {
    yield startSourceValue;
    startSourceValue = reverseMap[startSourceValue];
  }
  return;
}

for (let target of chainSources(a, 'target', 'source', '1')) {
  console.log(target);
}

const result = [...chainSources(a, 'target', 'source', '1')];

console.log(result);

Alternate solution without function generators:

const a = [
  { source: '2', target: '3' },
  { source: '1', target: '2' },
  { source: '3', target: '4' },
  { source: '4', target: '5' }
];
const startSource = '1';

function chainSources(array, targetKey, sourceKey, startSourceValue) {
  const res = [];
  const reverseMap = array.reduce((acc, item) => {
    acc[item[sourceKey]] = item[targetKey];
    return acc;
  }, {});

  while (reverseMap[startSourceValue] !== undefined) {
    res.push(startSourceValue);
    startSourceValue = reverseMap[startSourceValue];
  }
  return res;
}

const result = chainSources(a, 'target', 'source', '1');

console.log(result);

Answer №2

Within my code snippet, I am utilizing the .findIndex() array method to locate the index of an element in the array based on certain conditions. If the index returned is -1, it indicates that there is no data in the array that meets our specified condition.

const findElement = (value, array = [], tempArray = []) => {
  const index = array.findIndex((item) => { return item.name === value; });
  if (index > -1) {
    const element = array[index];
    tempArray.push(element.type);
    return findElement(element.type, array, tempArray);
  }
  return tempArray;
};

const data = [
  { name: 'apple', type: 'fruit' },
  { name: 'carrot', type: 'vegetable' },
  { name: 'banana', type: 'fruit' },
  { name: 'lettuce', type: 'vegetable' },
];
const startingValue = 'carrot';
const result = findElement(startingValue, data);
console.log(result); 

Answer №3

If you convert your current data structure into an object with the format {source: target}, you can then iterate through it until you reach a null node:

map = {};

for (let {source, target} of b) {
    map[source] = target;
}

while (current) {
    output.push(current);
    current = map[current];
}

This method relies on the assumption that your graph functions as a linear chain, where each source only has one target.

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

What is preventing my function from retrieving data from the JSON File?

Exploring the realm of JSON file manipulation, I am delving into how it functions. Equipped with a JSON file attached to my document and a function sharing the same name as my object in the JSON file. However, despite all efforts, the data is not being dis ...

Locate the word or phrase without a comma

I am currently working on a code that involves finding keys with string values separated by commas. var db = { "name": "Nkosana", "middle": "Baryy", "surname": "walked", "batch_number": "test,b", "temp": ",,67,6,87,86,5,67865,876,67" ...

Having difficulty choosing a default value from the Angular dropdown menu

My goal was to create a user-friendly address form that includes a country list for users to select when filling in their address information. The form is designed using ngForm, which not only collects the address but also allows users to edit their existi ...

The syntax in JavaScript of (0, fn)(args) is used to call

I came across an interesting piece of JavaScript code in Google's codebase that I wanted to discuss: var myVar = function...; (0, myVar)(args); Do you know what the significance of this syntax is? I'm struggling to see the difference between ( ...

Is there a way for Ionic to remember the last page for a few seconds before session expiry?

I have set the token for my application to expire after 30 minutes, and I have configured the 401/403 error handling as follows: // Handling 401 or 403 error async unauthorisedError() { const alert = await this.alertController.create({ header: 'Ses ...

Having trouble correctly parsing XML data using JavaScript

My input field contains the following XML code: <?xml version="1.0" encoding="utf-8"?> <players timestamp="1536505850"> <player id="0518" name="Eagles, Philadelphia" position="Def" team="PHI" /> <player id="10271" name="Jones, Jul ...

Angular: Unable to retrieve defined data when loading a component

There is a nagging question in my mind that I hesitate to ask because deep down, I know the answer is probably staring me in the face. After struggling with code for two days straight, I am on the brink of pulling my hair out. Although I am relatively new ...

Issue: Undefined onClick function for HTML when using Node.js, NPM, and Parcel

I am currently working on a weather application using Node.js, NPM, and Parcel for development. To ensure OpenLayers functions properly, I need to incorporate these technologies, even though I'm not very familiar with them. One key aspect of my proje ...

How can I achieve the functionality of an image changing when clicked and going back to its original state upon release with the help of HTML

I am facing an issue with styling an element to look like a button and function as a clickable link. My goal is to create a visual effect of a pressed button when it is clicked, while also loading the target page. For reference, here is a (non-working) J ...

ajax - unable to fetch information from the same domain

UPDATE: The solution provided by Cavid Kərimov indeed works. By setting the form as shown below, it also resolves the issue. <form onsubmit="return false;"></form> I am attempting to fetch a simple text string from a PHP file using jQuery an ...

Error: The function is not defined on this.props during the handleCHange event

After going through numerous answers to similar questions on this topic, I believe that I am following all the necessary steps but for some reason, it is not working. Below is the specific section of code that is causing the error: import React from &apos ...

Changing URI to File Object using JavaScript

I have successfully retrieved the URI of a selected file in my Ionic app using the cordova-fileChooser plugin. https://i.sstatic.net/NxXti.jpg Next, I used the cordova-plugin-filepath to obtain the absolute path of the file from the nativeURL on the phon ...

Mapped Generics in Typescript allows you to manipulate and

Currently, I am attempting to utilize TypeScript generics in order to transform them into a new object structure. Essentially, my goal is to change: { key: { handler: () => string }, key2: { hander: () => number }, } to: ...

Encountering an issue of THREE.EventDispatcher being undefined while trying to create a THREE.OrbitControls instance using THREE.js, THREE.OrbitControls, and TypeScript

Attempting to delve into typescript alongside three.js, I've encountered a perplexing error that has me stumped. The root of the issue lies within the init function where I initialize a new THREE.OrbitControls controller. Utilizing the setup provided ...

Exploring the functionality of surveyjs in conjunction with react and typescript

Does anyone have any code samples showcasing how to integrate Surveyjs with React and TypeScript? I attempted to import it into my project and utilized the code provided in this resource. https://stackblitz.com/edit/surveyjs-react-stackoverflow45544026 H ...

What can be done to ensure that two separate react-native Picker components do not interfere with each other's

Encountering an issue with two Pickers in a react-native View. Whenever I select a value in one Picker, it causes the other Picker to revert back to its initial item in the list. It seems like the onValueChange function is being triggered for both Pickers ...

Angular: The Process of Completely Updating a Model Object

Within my application, there is an object named eventData which acts as a singleton and is injected into multiple controllers through a resolve function. This eventData contains various sets of data such as drop down list values along with the main model. ...

Is there a method to compress all of my JS/CSS files before displaying them in the browser without doing so while editing them in the IDE?

I have a JavaScript file with numerous comments and unnecessary spaces, making it larger and slowing down the website. I am seeking a solution to minify the file when starting the server, while still being able to edit the original file in my IDE. Essen ...

Show a directional indicator on hover in the date selection tool

I am currently using a datepicker that looks like this: https://i.sstatic.net/XsrTO.png When I hover over it, three arrows appear to change days or show the calendar. However, I would like to remove these arrows. Here is the code snippet: link: functi ...

Mapping DOM elements to VueJS components for hydration is a key process in facilitating

I have a specific requirement and I am exploring potential solutions using VueJS, as it offers the convenient feature of hydrating pre-rendered HTML from the server. In my Vue components, I do not define a template within the .vue file, but I need them to ...