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
}
1 Answer 1
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.
2 Comments
.somes in the recursive regionPasses
subRegionofregionsregionsarray 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?