Reputation: 1128
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
}
Upvotes: 1
Views: 106
Reputation: 370599
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.
Upvotes: 3