简体   繁体   English

如何在 TypeScript/Javascript 中递归迭代对象数组

[英]How to iterate an array of objects recursively in TypeScript/Javascript

I have an array with objects that contains two properties: target and source .我有一个包含两个属性的对象的数组: targetsource Moreover, I have a starting source .此外,我有一个starting source

Now what I need to start with starting source and find a target from the array .现在我需要从starting source并从array找到一个target After finding the target , that value becomes source again find a target from that array .找到target ,该值变为source再次从该array查找target It should run recursively until target returned as undefined.它应该递归运行,直到目标返回为未定义。

What is the efficient way to do this?这样做的有效方法是什么?

I have implemented this problem as followed.我已经按如下方式实现了这个问题。 Some short and crisp code suggestion is required.需要一些简短明了的代码建议。

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);

Following is the recursive function以下是递归函数

 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;
    }
  }

You could create an hashmap or a plain object where the key is the source and the value is the target.您可以创建一个哈希图或一个普通对象,其中键是源,值是目标。 This will also avoid needing the recursive approach, since you really just need to process a chain until it's finished.这也将避免需要递归方法,因为您实际上只需要处理一个链直到它完成。

From that map, you could collect all values until map[nextSource] is undefined.从该地图中,您可以收集所有值,直到 map[nextSource] 未定义。

The below approach does exactly that and takes advantage of function generators to yield the values found.下面的方法正是这样做的,并利用函数生成器来生成找到的值。

This should be the most efficient way, since creating the lookup once and checking whether a key exists has O(1) complexity, while applying find for each iteration has an higher complexity (not sure how to calculate it properly, but it should be O(n) or O(n^2) complexity).这应该是最有效的方法,因为创建一次查找并检查键是否存在具有 O(1) 复杂度,而为每次迭代应用 find 具有更高的复杂度(不确定如何正确计算,但应该是 O (n) 或 O(n^2) 复杂度)。

If you don't want to, you can avoid using function generators and just collect the result and return it.如果你不想,你可以避免使用函数生成器,只收集结果并返回它。 I've decided to use them because I feel comfortable with their syntax and I like the fact that they are extremely easy to maintain.我决定使用它们是因为我对它们的语法感到满意,而且我喜欢它们非常容易维护的事实。

SIDE NOTE: in your sample code, you're firstly pushing a source , then some targets .旁注:在您的示例代码中,您首先推送一个source ,然后推送一些targets Since i'm not sure which you need to collect, I'm collecting source s.由于我不确定您需要收集哪些,因此我正在收集source If you need targets, just change yield startSourceValue;如果您需要目标,只需更改yield startSourceValue; to yield reverseMap[startSourceValue]; yield reverseMap[startSourceValue];

Below is the working code.下面是工作代码。

 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) { // Build an object where the [key] is the source property value and the [value] is the target property value. const reverseMap = array.reduce((acc, item) => { acc[item[sourceKey]] = item[targetKey]; return acc; }, {}); // Keep chaining the [target] value of initial [source] key until undefined while (reverseMap[startSourceValue] !== undefined) { yield startSourceValue; startSourceValue = reverseMap[startSourceValue]; } return; } // For..of usage for (let target of chainSources(a, 'target', 'source', '1')) { console.log(target); } // Spread usage. const result = [...chainSources(a, 'target', 'source', '1')]; console.log(result);

Same 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 = []; // Build an object where the [key] is the source property value and the [value] is the target property value. const reverseMap = array.reduce((acc, item) => { acc[item[sourceKey]] = item[targetKey]; return acc; }, {}); // Keep chaining the [target] value of initial [source] key until undefined while (reverseMap[startSourceValue] !== undefined) { res.push(startSourceValue); startSourceValue = reverseMap[startSourceValue]; } return res; } const result = chainSources(a, 'target', 'source', '1'); console.log(result);

You can convert your data structure to an object {source: target} first, and then simply loop until the current node is not null:您可以先将数据结构转换为对象{source: target} ,然后简单地循环直到当前节点不为空:

map = {};

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

while (start) {
    result.push(start);
    start = map[start];
}

This of course assumes that your graph is a chain, that is, each source has at most one target.这当然假设您的图是一个链,即每个源最多有一个目标。

In my snippet, I'm using .findIndex() array method which returns the index of the array between -1 to [].length based on applied conditions, If index return -1 It means there is no data present in an array which fall in our condition.在我的代码段中,我使用.findIndex()返回的数组的索引阵列的方法-1[].length基于施加的条件下,如果索引返回-1这意味着没有存在于阵列中的数据,其落在我们的条件。

 const findTarget = (string, array = [], tempArray = []) => { const index = array.findIndex((i) => { return i.source === string; }); if (index > -1) { const element = array[index]; tempArray.push(element.target); return findTarget(element.target, array, tempArray); } return tempArray; }; const input = [ { source: '2', target: '3' }, { source: '1', target: '2' }, { source: '3', target: '4' }, { source: '4', target: '5' }, ]; const startSource = '1'; const output = findTarget(startSource, input); console.log(output);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM