Considérez le tableau profondément imbriqué suivant:

const array = [
    {
        id: 1,
        name: "bla",
        children: [
            {
                id: 23,
                name: "bla",
                children: [{ id: 88, name: "bla" }, { id: 99, name: "bla" }]
            },
            { id: 43, name: "bla" },
            {
                id: 45,
                name: "bla",
                children: [{ id: 43, name: "bla" }, { id: 46, name: "bla" }]
            }
        ]
    },
    {
        id: 12,
        name: "bla",
        children: [
            {
                id: 232,
                name: "bla",
                children: [{ id: 848, name: "bla" }, { id: 959, name: "bla" }]
            },
            { id: 433, name: "bla" },
            {
                id: 445,
                name: "bla",
                children: [
                    { id: 443, name: "bla" },
                    {
                        id: 456,
                        name: "bla",
                        children: [
                            {
                                id: 97,
                                name: "bla"
                            },
                            {
                                id: 56,
                                name: "bla"
                            }
                        ]
                    }
                ]
            }
        ]
    },
    {
        id: 15,
        name: "bla",
        children: [
            {
                id: 263,
                name: "bla",
                children: [{ id: 868, name: "bla" }, { id: 979, name: "bla" }]
            },
            { id: 483, name: "bla" },
            {
                id: 445,
                name: "bla",
                children: [{ id: 423, name: "bla" }, { id: 436, name: "bla" }]
            }
        ]
    }
];

Comment pourrais-je saisir un certain objet par clé qui pourrait être profondément imbriqué, en utilisant la récursivité? J'ai essayé cela, mais cela ne fonctionnera pas pour une imbrication plus profonde que 2 niveaux, il retourne alors simplement undefined:

const findItemNested = (arr, itemId, nestingKey) => {
    for (const i of arr) {
        console.log(i.id);
        if (i.id === itemId) {
            return i;
        }
        if (i[nestingKey]) {
            findItemNested(i[nestingKey], itemId, nestingKey);
        }
    }
};

Le résultat devrait être:

const res = findItemNested(array, 959, "children"); >> { id: 959, name: "bla" }

Cela peut peut-être aussi être réalisé en utilisant .find, ou tout simplement pour aplatir le tableau (par la clé enfants), mais l'utilisation de la récursion semble être la solution la plus logique pour moi. Quelqu'un at-il une solution à cela?

Merci d'avance :).

9
Fabian Tjoe A On 20 nov. 2018 à 12:59

6 réponses

Meilleure réponse

Vous pouvez utiliser un reduce récursif:

const array=[{id:1,name:"bla",children:[{id:23,name:"bla",children:[{id:88,name:"bla"},{id:99,name:"bla"}]},{id:43,name:"bla"},{id:45,name:"bla",children:[{id:43,name:"bla"},{id:46,name:"bla"}]}]},{id:12,name:"bla",children:[{id:232,name:"bla",children:[{id:848,name:"bla"},{id:959,name:"bla"}]},{id:433,name:"bla"},{id:445,name:"bla",children:[{id:443,name:"bla"},{id:456,name:"bla",children:[{id:97,name:"bla"},{id:56,name:"bla"}]}]}]},{id:15,name:"bla",children:[{id:263,name:"bla",children:[{id:868,name:"bla"},{id:979,name:"bla"}]},{id:483,name:"bla"},{id:445,name:"bla",children:[{id:423,name:"bla"},{id:436,name:"bla"}]}]}];

const findItemNested = (arr, itemId, nestingKey) => (
  arr.reduce((a, item) => {
    if (a) return a;
    if (item.id === itemId) return item;
    if (item[nestingKey]) return findItemNested(item[nestingKey], itemId, nestingKey)
  }, null)
);
const res = findItemNested(array, 959, "children");
console.log(res);
12
CertainPerformance 20 nov. 2018 à 10:05

Vous devez parcourir vos objets, puis analyser chaque objet à l'aide de la récursivité. Essayez la réponse mentionnée ici: Recherche récursive JavaScript dans un objet JSON

Code:

`fonction findNode (id, currentNode) {var i, currentChild, result;

if (id == currentNode.id) {
    return currentNode;
} else {

    // Use a for loop instead of forEach to avoid nested functions
    // Otherwise "return" will not work properly
    for (i = 0; i < currentNode.children.length; i += 1) {
        currentChild = currentNode.children[i];

        // Search in the current child
        result = findNode(id, currentChild);

        // Return the result if the node has been found
        if (result !== false) {
            return result;
        }
    }

    // The node has not been found and we have no more options
    return false;
}

} `

-2
partizanos 20 nov. 2018 à 10:04

Cela devrait fonctionner:

function findByIdRecursive(array, id) {
  for (let index = 0; index < array.length; index++) {
    const element = array[index];
    if (element.id === id) {
      return element;
    } else {
      if (element.children) {
        const found = findByIdRecursive(element.children, id);

        if (found) {
          return found;
        }
      }
    }
  }
}
0
ritaj 20 nov. 2018 à 10:12

Vous pouvez également utiliser la récursivité avec Array.find comme ci-dessous

const array=[{id:1,name:"bla",children:[{id:23,name:"bla",children:[{id:88,name:"bla"},{id:99,name:"bla"}]},{id:43,name:"bla"},{id:45,name:"bla",children:[{id:43,name:"bla"},{id:46,name:"bla"}]}]},{id:12,name:"bla",children:[{id:232,name:"bla",children:[{id:848,name:"bla"},{id:959,name:"bla"}]},{id:433,name:"bla"},{id:445,name:"bla",children:[{id:443,name:"bla"},{id:456,name:"bla",children:[{id:97,name:"bla"},{id:56,name:"bla"}]}]}]},{id:15,name:"bla",children:[{id:263,name:"bla",children:[{id:868,name:"bla"},{id:979,name:"bla"}]},{id:483,name:"bla"},{id:445,name:"bla",children:[{id:423,name:"bla"},{id:436,name:"bla"}]}]}];


function findById(arr, id, nestingKey) {
  
  // if empty array then return
  if(arr.length == 0) return
  
  // return element if found else collect all children(or other nestedKey) array and run this function
  return arr.find(d => d.id == id) 
      || findById(arr.flatMap(d => d[nestingKey] || []), id) 
      || 'Not found'
}

console.log(findById(array, 12, 'children'))

console.log(findById(array, 483, 'children'))

console.log(findById(array, 1200, 'children'))
4
Nitish Narang 20 nov. 2018 à 12:04

Tu peux faire:

const array=[{id:1,name:"bla",children:[{id:23,name:"bla",children:[{id:88,name:"bla"},{id:99,name:"bla"}]},{id:43,name:"bla"},{id:45,name:"bla",children:[{id:43,name:"bla"},{id:46,name:"bla"}]}]},{id:12,name:"bla",children:[{id:232,name:"bla",children:[{id:848,name:"bla"},{id:959,name:"bla"}]},{id:433,name:"bla"},{id:445,name:"bla",children:[{id:443,name:"bla"},{id:456,name:"bla",children:[{id:97,name:"bla"},{id:56,name:"bla"}]}]}]},{id:15,name:"bla",children:[{id:263,name:"bla",children:[{id:868,name:"bla"},{id:979,name:"bla"}]},{id:483,name:"bla"},{id:445,name:"bla",children:[{id:423,name:"bla"},{id:436,name:"bla"}]}]}];
const findItemNested = (arr, itemId, nestingKey) => arr.reduce((a, c) => {
  return a.length
    ? a
    : c.id === itemId
      ? a.concat(c)
      : c[nestingKey]
        ? a.concat(findItemNested(c[nestingKey], itemId, nestingKey))
        : a
}, []);
const res = findItemNested(array, 959, "children");

if (res.length) {
  console.log(res[0]);
}
0
Yosvel Quintero 20 nov. 2018 à 10:22

Cela utilisera la recherche récursive par niveau, il essaiera de trouver l'élément dans le tableau, puis s'appellera avec les enfants de chaque élément du tableau:

Les nouveaux navigateurs auront Array.prototype.flatten mais dans ce cas, j'ai ajouté la fonction d'aplatissement séparément.

const array = [{"id":1,"name":"bla","children":[{"id":23,"name":"bla","children":[{"id":88,"name":"bla"},{"id":99,"name":"bla"}]},{"id":43,"name":"bla"},{"id":45,"name":"bla","children":[{"id":43,"name":"bla"},{"id":46,"name":"bla"}]}]},{"id":12,"name":"bla","children":[{"id":232,"name":"bla","children":[{"id":848,"name":"bla"},{"id":959,"name":"bla"}]},{"id":433,"name":"bla"},{"id":445,"name":"bla","children":[{"id":443,"name":"bla"},{"id":456,"name":"bla","children":[{"id":97,"name":"bla"},{"id":56,"name":"bla"}]}]}]},{"id":15,"name":"bla","children":[{"id":263,"name":"bla","children":[{"id":868,"name":"bla"},{"id":979,"name":"bla"}]},{"id":483,"name":"bla"},{"id":445,"name":"bla","children":[{"id":423,"name":"bla"},{"id":436,"name":"bla"}]}]}];


const flatten = (arr) =>
  arr.reduce((result, item) => result.concat(item), []);
const findBy = (findFunction, subItemsKey) => (array) =>
  //array is empty (can be when children of children of children does not exist)
  array.length === 0
    ? undefined //return undefined when array is empty
    : array.find(findFunction) || //return item if found
      findBy(findFunction, subItemsKey)(//call itself when item is not found
        flatten(
          //take children from each item and flatten it
          //([[child],[child,child]])=>[child,child,child]
          array.map((item) => item[subItemsKey] || []),
        ),
      );
const findChildrenById = (array) => (value) =>
  findBy((item) => item.id === value, 'children')(array);
const findInArray = findChildrenById(array);

console.log('found', findInArray(99));
console.log('not found', findInArray({}));
0
HMR 20 nov. 2018 à 11:37