1

I have the following object:

const obj = {
  alphas: {
    top: [{name: "q"}, {name: "w"}],
    middle: [{name: "a"}, {name: "s"}],
    bottom: [{name: "z"}, {name: "x"}],
  },
  numbers: {
    low: [{name: "1"}, {name: "2"}, {name: "3"}],
    high: [{name: "1000"}, {name: "2000"}],
  }
}

I need the nested indexes of the name.
For instance, if I'm looking for "s" the result should be the array [0, 1]:

  • 0 because "s" is in the first category (alphas)
  • 1 because "s" is in the second subcategory (middle).

I'm able to find the indexes in separate loops:

const categoryIndex = Object.keys(obj).findIndex(
  cat => Object.keys(obj[cat]).some(
    subcat => obj[cat][subcat].some(
      key => key.name === "s")));

const categoryName = Object.keys(obj)[categoryIndex];
const subcategoryIndex = Object.keys(obj[categoryName]).findIndex(
  subcat => obj[categoryName][subcat].some(key => key.name === "s"));

const result = [categoryIndex, subcategoryIndex];

https://jsfiddle.net/7w523ojn/

Having two separate loops may cost too much so I'm looking for a way to get indexes at once. Something like this:

[categoryIndex , subcategoryIndex] = ...

Is there a way to get nested indexes at once? Solutions involving Lodash, Ramda and whatnot are also welcome. Thank you.

Dacre Denny
  • 26,362
  • 5
  • 28
  • 48
isar
  • 1,390
  • 15
  • 28
  • This would work only if the properties are added in the same order as it is mentioned in the question. You are better off getting `["alphas", "middle"]` as the output instead of `[0, 1]`. See: [Does JavaScript Guarantee Object Property Order?](https://stackoverflow.com/a/38218582/3082296) – adiga Apr 07 '19 at 10:45

1 Answers1

1

If I understand you question correctly, then this can be achieve via a recursive search and return function, as detailed below:

const obj={alphas:{top:[{name:"q"},{name:"w"}],middle:[{name:"a"},{name:"s"}],bottom:[{name:"z"},{name:"x"}]},numbers:{low:[{name:"1"},{name:"2"},{name:"3"}],high:[{name:"1000"},{name:"2000"}]}};

const recursiveSearch = (object, searchFor) => {

  let index = 0;
  for (const key in object) {
    const value = object[key];

    if (Array.isArray(value)) {

      /* If object value is an array, iterate through it and 
      search for item with name field matching searchFor 
      character */
      const array = value;
      for (let i = 0; i < array.length; i++) {

        /* If array item's name matches searchFor charater
        then return this as the first entry in our results 
        array */
        if (array[i].name === searchFor) {
          return [index, i];
        }
      }
    } else if (typeof object === "object") {

      /* If object value is object, then recursivly search
      through children for a result. If an result is found,
      prepend the current key's index to the result array */
      const result = recursiveSearch(value, searchFor);

      /* Array.isArray() tells us this call to recursiveSearch()
      found a result, so we are to return from this call */
      if (Array.isArray(result)) {
        return [index].concat(result);
      }
    }

    index++;
  }
};

console.log('indicies for "s":', recursiveSearch(obj, 's'));
Dacre Denny
  • 26,362
  • 5
  • 28
  • 48