étant donné le json ci-dessous
[
{
id: 'myId1',
value: 'Tree View top level 1',
},
{
id: 'myId2',
value: 'Tree View top level 2',
},
{
id: 'myId3',
value: 'Tree View second level 1',
},
{
id: 'myId3',
value: 'Tree View second level 2',
},
]
où les collections nommées "fetchedChildren" imbriquées pourraient durer à l'infini
Existe-t-il un moyen simple de l'aplatir en un seul tableau comme celui-ci ?
[
{
id: 'myId1',
value: 'Tree View top level 1',
fetchedChildren: []
},
{
id: 'myId2',
value: 'Tree View top level 2',
fetchedChildren: [
{
id: 'myId3',
value: 'Tree View second level 1',
fetchedChildren: []
},
{
id: 'myId4',
value: 'Tree View second level 2',
fetchedChildren: []
},
]
},
]
J'ai vu beaucoup d'exemples qui font cela avec des objets imbriqués qui n'ont pas de collections nommées, mais je n'ai pas vu ou pourrais comprendre comment faire cela dans ce scénario
5 Réponses :
La récursivité est le moyen pour toute recherche en profondeur d'abord sur un arbre:
let arr=[
{
id: 'myId1',
value: 'Tree View top level 1',
fetchedChildren: []
},
{
id: 'myId2',
value: 'Tree View top level 2',
fetchedChildren: [
{
id: 'myId3',
value: 'Tree View second level 1',
fetchedChildren: []
},
{
id: 'myId4',
value: 'Tree View second level 2',
fetchedChildren: []
},
]
},
];
function flatten(a){
var result=[];
for (let e of a) {
result.push({id:e.id,value:e.value})
result=result.concat(flatten(e.fetchedChildren));
}
return result;
}
console.log(flatten(arr));
Voici ce que vous voulez: (n'utilisez pas la récursivité car vous pourriez déborder la pile d'appels car vous dites qu'elle pourrait avoir un nombre infini de couches)
const ar = [{
id: 'myId1',
value: 'Tree View top level 1',
fetchedChildren: []
}, {
id: 'myId2',
value: 'Tree View top level 2',
fetchedChildren: [{
id: 'myId3',
value: 'Tree View second level 1',
fetchedChildren: [{
id: 'myId5',
value: 'Tree View thrid level 1',
fetchedChildren: []
}]
}, {
id: 'myId4',
value: 'Tree View second level 2',
fetchedChildren: []
}]
}];
for (var i = 0; i < ar.length; i++) {
if (ar[i].fetchedChildren.length) {
ar.push(...ar[i].fetchedChildren);
}
delete ar[i].fetchedChildren;
}
console.log(ar);
Vous devez utiliser la récursivité car l'imbrication peut aller arbitrairement en profondeur.
C'est exactement le contraire, car l'imbrication peut aller arbitrairement en profondeur, vous ne devez pas utiliser la récursivité car la pile d'appels pourrait être arbitrairement débordée.
Bien. La taille des données doit être gérée par le codeur ailleurs. De plus, les compilateurs modernes peuvent optimiser la récursivité de la queue. D'après ce que je peux dire, votre code ne peut gérer que deux niveaux.
Je pense que mon code pourrait gérer n'importe quel nombre de niveau (j'ai édité l'exemple avec un troisième niveau supplémentaire)
OK j'ai compris. La vôtre est une approche globale, n'est-ce pas? Il est apparemment plus efficace en mémoire.
C'est aussi destructeur, ce qui m'inquiéterait beaucoup. Je préfère de loin le code qui ne mute pas son entrée.
Vous pouvez utiliser une méthode flatMap et obtenir tous les enfants en détruisant les enfants de l'objet.
.as-console-wrapper { max-height: 100% !important; top: 0; }
var getFlat = ({ fetchedChildren, ...o }) => [o, ...fetchedChildren.flatMap(getFlat)],
data = [{ id: 'myId1', value: 'Tree View top level 1', fetchedChildren: [] }, { id: 'myId2', value: 'Tree View top level 2', fetchedChildren: [{ id: 'myId3', value: 'Tree View second level 1', fetchedChildren: [] }, { id: 'myId4', value: 'Tree View second level 2', fetchedChildren: [] }] }],
flat = data.flatMap(getFlat);
console.log(flat);
Vous pouvez réduire pour exécuter un extracteur récursif.
const data = [
{
id: 'myId1',
value: 'Tree View top level 1',
fetchedChildren: []
},
{
id: 'myId2',
value: 'Tree View top level 2',
fetchedChildren: [
{
id: 'myId3',
value: 'Tree View second level 1',
fetchedChildren: []
},
{
id: 'myId4',
value: 'Tree View second level 2',
fetchedChildren: []
},
]
},
]
const extract = (acc, item) => {
const value = Object.keys(item)
.filter(k => k !== 'fetchedChildren')
.map(k => ([k, item[k]]))
.reduce((res, [k,v]) => ({...res, [k]: v}), {})
const children = item.fetchedChildren.reduce(extract, [])
return [...acc, value, ...children]
}
const result = data.reduce(extract, [])
console.log(data)
console.log(result)
La déstructuration des paramètres peut nous aider à écrire une récursion simple pour ce cas:
const flatten = ([{fetchedChildren = undefined, ... rest} = {}, ... xs], res = []) =>
fetchedChildren == undefined
? res
: flatten ([... xs, ... fetchedChildren], [...res, rest])
.as-console-wrapper {min-height: 100% !important; top: 0}
Et une variation récursive de queue n'est pas beaucoup plus complexe:
const flatten = ([{fetchedChildren = undefined, ... rest} = {}, ... xs]) =>
fetchedChildren == undefined
? []
: [rest, ... flatten ([... xs, ... fetchedChildren])]
const ar = [{id: 'myId1', value: 'Tree View top level 1', fetchedChildren: []}, {id: 'myId2', value: 'Tree View top level 2', fetchedChildren: [{id: 'myId3', value: 'Tree View second level 1', fetchedChildren: [{id: 'myId5', value: 'Tree View thrid level 1', fetchedChildren: []}]}, {id: 'myId4', value: 'Tree View second level 2', fetchedChildren: []}]}];
console .log (flatten (ar))
Sera-ce toujours une seule couche de profondeur, ou plus?
plus - pourrait durer éternellement en théorie