Hiermee raakte ik een muur en dacht ik post het hier voor het geval een vriendelijke ziel een soortgelijk exemplaar is tegengekomen. Ik heb gegevens die er ongeveer zo uitzien:
const input = [
{
value: 'Miss1',
children: [
{ value: 'Miss2' },
{ value: 'Hit1', children: [ { value: 'Miss3' } ] }
]
},
{
value: 'Miss4',
children: [
{ value: 'Miss5' },
{ value: 'Miss6', children: [ { value: 'Hit2' } ] }
]
},
{
value: 'Miss7',
children: [
{ value: 'Miss8' },
{ value: 'Miss9', children: [ { value: 'Miss10' } ] }
]
},
{
value: 'Hit3',
children: [
{ value: 'Miss11' },
{ value: 'Miss12', children: [ { value: 'Miss13' } ] }
]
},
{
value: 'Miss14',
children: [
{ value: 'Hit4' },
{ value: 'Miss15', children: [ { value: 'Miss16' } ] }
]
},
];
Ik weet tijdens runtime niet hoe diep de hiërarchie zal zijn, d.w.z. hoeveel niveaus van objecten een onderliggende array zullen hebben. Ik heb het voorbeeld enigszins vereenvoudigd, ik zal de waarde-eigenschappen eigenlijk moeten matchen met een reeks zoektermen. Laten we voorlopig aannemen dat ik match met waar value.includes('Hit')
.
Ik heb een functie nodig die een nieuwe array retourneert, zodanig dat:
-
Elk niet-overeenkomend object zonder kinderen, of geen overeenkomsten in de onderliggende hiërarchie, zou niet moeten bestaan in het uitvoerobject
-
Elk object met een afstammeling dat een overeenkomend object bevat, moet blijven
-
Alle nakomelingen van overeenkomende objecten moeten blijven
Ik beschouw een ‘overeenkomstig object’ als een object met een value
-eigenschap die in dit geval de tekenreeks Hit
bevat, en vice versa.
De uitvoer zou er ongeveer als volgt uit moeten zien:
const expected = [
{
value: 'Miss1',
children: [
{ value: 'Hit1', children: [ { value: 'Miss3' } ] }
]
},
{
value: 'Miss4',
children: [
{ value: 'Miss6', children: [ { value: 'Hit2' } ] }
]
},
{
value: 'Hit3',
children: [
{ value: 'Miss11' },
{ value: 'Miss12', children: [ { value: 'Miss13' } ] }
]
},
{
value: 'Miss14',
children: [
{ value: 'Hit4' },
]
}
];
Veel dank aan iedereen die de tijd heeft genomen om tot hier te lezen, zal mijn oplossing posten als ik daar als eerste ben.
Antwoord 1, autoriteit 100%
Het gebruik van .filter()
en het maken van een recursieve aanroep zoals ik in de bovenstaande opmerking heb beschreven, is eigenlijk wat je nodig hebt. U hoeft alleen elke eigenschap van .children
bij te werken met het resultaat van de recursieve aanroep voordat u terugkeert.
De geretourneerde waarde is gewoon de .length
van de resulterende verzameling .children
, dus als er minstens één is, blijft het object behouden.
var res = input.filter(function f(o) {
if (o.value.includes("Hit")) return true
if (o.children) {
return (o.children = o.children.filter(f)).length
}
})
Antwoord 2, autoriteit 20%
Hier is een functie die doet wat u zoekt. In wezen zal het elk item in arr
testen op een overeenkomst, en vervolgens recursief het filter aanroepen op zijn children
. Ook wordt Object.assign
gebruikt, zodat het onderliggende object niet wordt gewijzigd.
function filter(arr, term) {
var matches = [];
if (!Array.isArray(arr)) return matches;
arr.forEach(function(i) {
if (i.value.includes(term)) {
matches.push(i);
} else {
let childResults = filter(i.children, term);
if (childResults.length)
matches.push(Object.assign({}, i, { children: childResults }));
}
})
return matches;
}
Antwoord 3, autoriteit 3%
Ik denk dat het een recursieve oplossing zal zijn. Hier is er een die ik heb geprobeerd.
function find(obj, key) {
if (obj.value && obj.value.indexOf(key) > -1){
return true;
}
if (obj.children && obj.children.length > 0){
return obj.children.reduce(function(obj1, obj2){
return find(obj1, key) || find(obj2, key);
}, {});
}
return false;
}
var output = input.filter(function(obj){
return find(obj, 'Hit');
});
console.log('Result', output);
Antwoord 4, autoriteit 2%
const input = [
{
value: 'Miss1',
children: [
{ value: 'Miss1' },
{ value: 'Hit1', children: [ { value: 'Miss3' } ] }
]
},
{
value: 'Miss4',
children: [
{ value: 'Miss5' },
{ value: 'Miss6', children: [ { value: 'Hit2' } ] }
]
},
{
value: 'Miss7',
children: [
{ value: 'Miss8' },
{ value: 'Miss9', children: [ { value: 'Miss10' } ] }
]
},
{
value: 'Hit3',
children: [
{ value: 'Miss11' },
{ value: 'Miss12', children: [ { value: 'Miss13' } ] }
]
},
{
value: 'Miss14asds',
children: [
{ value: 'Hit4sdas' },
{ value: 'Miss15', children: [ { value: 'Miss16' } ] }
]
},
];
function filter(arr, term) {
var matches = [];
if (!Array.isArray(arr)) return matches;
arr.forEach(function(i) {
if (i.value === term) {
const filterData = (i.children && Array.isArray(i.children))? i.children.filter(values => values.value ===term):[];
console.log(filterData)
i.children =filterData;
matches.push(i);
} else {
// console.log(i.children)
let childResults = filter(i.children, term);
if (childResults.length)
matches.push(Object.assign({}, i, { children: childResults }));
}
})
return matches;
}
const filterData= filter(input,'Miss1');
console.log(filterData)
Antwoord 5
Was op zoek naar een andere manier om dit probleem op te lossen zonder de kinderarray direct te muteren en kwam met dit:
const input = [
{
value: 'Miss1',
children: [
{ value: 'Miss2' },
{ value: 'Hit1', children: [ { value: 'Miss3' } ] }
]
},
{
value: 'Miss4',
children: [
{ value: 'Miss5' },
{ value: 'Miss6', children: [ { value: 'Hit2' } ] }
]
},
{
value: 'Miss7',
children: [
{ value: 'Miss8' },
{ value: 'Miss9', children: [ { value: 'Miss10' } ] }
]
},
{
value: 'Hit3',
children: [
{ value: 'Miss11' },
{ value: 'Miss12', children: [ { value: 'Miss13' } ] }
]
},
{
value: 'Miss14',
children: [
{ value: 'Hit4' },
{ value: 'Miss15', children: [ { value: 'Miss16' } ] }
]
},
];
const filtered = input.reduce(function fr(acc, curr) {
if (curr.children) {
const children = curr.children.reduce(fr, []);
if (children.length) {
return acc.concat({ ...curr, children: children });
}
}
if (curr.value.includes('Hit')) {
return acc.concat(curr);
} else {
return acc;
}
}, []);
console.log(filtered);