1

I want to create a function that gets the "parent" in a recursive array loop, and make an output array of those "used" parents.

It's a bit hard to explain, but take a look at the example:

const regions = [{
  name: 'Europe',
  subRegions: [{
    name: 'BeNeLux',
    territories: [{
      code: 'NL',
      name: 'Netherlands'
    }, {
      code: 'DE',
      name: 'Germany'
    }, {
      code: 'LU',
      name: 'Luxembourg'
    }]
  }],
  territories: [{
    code: 'UK',
    name: 'United Kingdom'
  }, {
    code: 'AL',
    name: 'Albania'
  }, {
    code: 'ZW',
    name: 'Switzerland'
  }]
}, {
  name: 'Africa',
  territories: [{
    code: 'GH',
    name: 'Ghana'
  }]
}]

const selectedTerritories = ['NL', 'UK', 'GH']

At this point I need a function, that searches for all the TOP regions of a territory by code, so the output would look like this:

const activeRegions = ['Europe', 'Africa']

A thing to note is that, there is a subRegion within Europe (BeNeLux), and the recursion gets to that point, it should NOT return BeNeLux as an active region but Europe instead.

This is what I have tried, but has duplicate subregion names and it ignores the "parent" recursion discover requirement:

const getRegionsLabelFromTerritoryList = (activeTerritories, regions, activeRegions = []) => {
  regions.forEach((region) => {
    if (region.territories) {
      region.territories.forEach(t => {
        if (activeTerritories.includes(t.code)) {
          activeRegions.push(region)
        }
      })
    }

    if (region.subRegions) {
      getRegionsLabelFromTerritoryList(region.subRegions, activeRegions)
    }
  })

  return activeRegions
}
4
  • This no longer looks like it requires recursion. I see no recursive substructures anymore. Commented Aug 3, 2019 at 22:53
  • @PatrickRoberts Hmm, it feel to me that it should be solved recursively as there can be an infinite level of depth in subRegion of regions Commented Aug 3, 2019 at 22:58
  • 1
    Are you sure the input structure is the way you posted it? Right now, the top level regions array contains one object (Europe), and one array (an array which contains Africa), which seems quite unusual. Should the Africa object be on the top level of the outer array instead? Commented Aug 3, 2019 at 23:06
  • @CertainPerformance Oops, it's late here... fixed Commented Aug 3, 2019 at 23:19

1 Answer 1

3

Assuming that the Africa object is supposed to be on the top level, filter the top-level objects by whether their subRegions satisfy the recursive test (a test that checks whether selectedTerritories includes the code of the object being iterated over, or whether any of the subRegions children pass the test):

const regions = [{
  name: 'Europe',
  subRegions: [{
    name: 'BeNeLux',
    territories: [{
      code: 'NL',
      name: 'Netherlands'
    }, {
      code: 'DE',
      name: 'Germany'
    }, {
      code: 'LU',
      name: 'Luxembourg'
    }]
  }],
  territories: [{
    code: 'UK',
    name: 'United Kingdom'
  }, {
    code: 'AL',
    name: 'Albania'
  }, {
    code: 'ZW',
    name: 'Switzerland'
  }]
}, {
  name: 'Africa',
  territories: [{
    code: 'GH',
    name: 'Ghana'
  }]
}];

const selectedTerritories = ['NL', 'UK', 'GH'];

const regionPasses = ({ subRegions, territories }) => (
  territories.some(({ code }) => selectedTerritories.includes(code))
  || (subRegions && subRegions.some(regionPasses))
);
    
const topSelected = regions
  .filter(regionPasses)
  .map(({ name }) => name);
console.log(topSelected);

To make things less computationally complex, you could turn selectedTerritories into a Set first (turning an O(n) operation into an O(1) operation):

const regions = [{
  name: 'Europe',
  subRegions: [{
    name: 'BeNeLux',
    territories: [{
      code: 'NL',
      name: 'Netherlands'
    }, {
      code: 'DE',
      name: 'Germany'
    }, {
      code: 'LU',
      name: 'Luxembourg'
    }]
  }],
  territories: [{
    code: 'UK',
    name: 'United Kingdom'
  }, {
    code: 'AL',
    name: 'Albania'
  }, {
    code: 'ZW',
    name: 'Switzerland'
  }]
}, {
  name: 'Africa',
  territories: [{
    code: 'GH',
    name: 'Ghana'
  }]
}];

const selectedTerritories = new Set(['NL', 'UK', 'GH']);

const regionPasses = ({ subRegions, territories }) => (
  territories.some(({ code }) => selectedTerritories.has(code))
  || (subRegions && subRegions.some(regionPasses))
);
    
const topSelected = regions
  .filter(regionPasses)
  .map(({ name }) => name);
console.log(topSelected);

You could achieve the same result with a single outer loop rather than two (.reduce or something instead of .filter followed by .map), but I think this is clearer.

Sign up to request clarification or add additional context in comments.

2 Comments

For some reason this is not working for me, check this codepen: codepen.io/anon/pen/ymzGgZ?editors=1111 it should only output Europe instead
Oops, there need to be two .somes in the recursive regionPasses

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.