Felix
Felix

Reputation: 1810

In Angular / TS how to structure Observable for search of a tree of objects - Key, Value type?

I have a simple interface with 2 properties k,v (key, value).

export interface KV {
    k: string;
    v: any
}

This is a base for variety of nested objects of the same type - KV, where v: may contain nested sub-objects of KV and finally arriving to last/leaf object of the tree where v: is string - not of KV type.

Example: (the hierarchy is reversed in this example - the last table is on top -contains the entries where v (value) is string. The following nodes are parent nodes, bottom node is the root node.

const tableC2: KV[] = [
    { k: 'TXT1',  v: 'text 1'},
    { k: 'TXT2',  v: 'text 2'},
    { k: 'TXT3',  v: 'text 3'},
    ....
];

const tableB1: KV[] = [
    { k: 'C1',  v: tableC1},
    { k: 'C2',  v: tableC2},      // <--- tableC2 above
    { k: 'C3',  v: tableC3},
    ....
];

const tableA: KV[] = [
    { k: 'A1',  v: tableA1},
    { k: 'A2',  v: tableA2},
    { k: 'B1',  v: tableB1},      // <--- tableB1 above
    ....
]

Now, having object: tableA as the initial data source set as Observable:

tbl$ = of(tableA);

What would be the most efficient way to set up async / Observable to search the tree hierarchy for a key e.g. key = 'TXT3' and get its v/value - 'text 3', so we can place the observable in the Angular template using the | async pipe?

In a regular / sync approach I have something like this:

 private findText(nodes: KV[], key: string): any {
    let d: KV[];
    for (let n of nodes) {
                    // navigate to last child node, where v
                    // is no longer of another KV (k,v) type
      while(n.hasOwnProperty('k') && n.hasOwnProperty('v')) {
        d = n.v;
        n = n.v;
      }
      let result = d.find(e => e.k === key);
      if (result) {
        return result.v;
      }
    }
    return undefined;
  }

This works OK.

How do we make this function async?

Something like this ( but this is just an idea and I get lost at more complex levels):

  public findText(nodes$: Observable<KV[]>, key: string): Observable<any> {
    return nodes$.pipe(switchMap(e => 
      e.forEach(n => 
      n.v.filter(v => ( ! v.hasOwnProperty('k') && ! v.hasOwnProperty('v')))
      .filter(t => (t === key))
      .map(r => r.v))));
  }

Upvotes: 0

Views: 274

Answers (1)

MoxxiManagarm
MoxxiManagarm

Reputation: 9134

You can still use the sync approach.

public findText(nodes$: Observable<KV[]>, key: string): Observable<any> {
    return nodes$.pipe(map(nodes => findTextSync(nodes, key)));
  }

Upvotes: 1

Related Questions