118 votes

Recherche par clé profonde dans un tableau imbriqué

Disons que j'ai un objet :

[
    {
        'title': "some title"
        'channel_id':'123we'
        'options': [
                    {
                'channel_id':'abc'
                'image':'http://asdasd.com/all-inclusive-block-img.jpg'
                'title':'All-Inclusive'
                'options':[
                    {
                        'channel_id':'dsa2'
                        'title':'Some Recommends'
                        'options':[
                            {
                                'image':'http://www.asdasd.com'                                 'title':'Sandals'
                                'id':'1'
                                'content':{
                                     ...

Je veux trouver l'objet dont l'identifiant est 1. Existe-t-il une fonction pour quelque chose comme ça ? Je pourrais utiliser la fonction Underscore _.filter mais je devrais commencer par le haut et filtrer vers le bas.

10voto

spuhgetty Points 129

Si vous êtes à fond dans l'ES6, vous pouvez utiliser

const findByKey = (obj, kee) => {
    if (kee in obj) return obj[kee];
    for(n of Object.values(obj).filter(Boolean).filter(v => typeof v === 'object')) {
        let found = findByKey(n, kee)
        if (found) return found
    }
}

const findByProperty = (obj, predicate) => {
    if (predicate(obj)) return obj
    for(n of Object.values(obj).filter(Boolean).filter(v => typeof v === 'object')) {
        let found = findByProperty(n, predicate)
        if (found) return found
    }
}

trouver par valeur va être un peu différent.

let findByValue = (o, val) => {
    if (o === val) return o;
    if (o === NaN || o === Infinity || !o || typeof o !== 'object') return;
    if (Object.values(o).includes(val)) return o;
    for (n of Object.values(o)) {
        const found = findByValue(n, val)
        if (found) return n
    }
}

alors ils peuvent être utilisés comme suit

const arry = [{ foo: 0 }, null, { bar: [{ baz: { nutherKey: undefined, needle: "gotcha!" } }]}]
const obj = { alice: Infinity, bob: NaN, charlie: "string", david: true, ebert: arry }

findByKey(obj, 'needle')
// 'gotcha!'

findByProperty(obj, val => val.needle === 'gotcha!')
// { nutherKey: undefined, needle: "gotcha!" }

findByValue(obj, 'gotcha!')
// { nutherKey: undefined, needle: "gotcha!" }

8voto

Alex Quan Points 81

J'ai trouvé cette page en cherchant sur Google des fonctionnalités similaires. Sur la base du travail fourni par Zach et regularmike, j'ai créé une autre version qui répond à mes besoins.
BTW, travail teriffic Zah et regularmike ! Je vais poster le code ici :

function findObjects(obj, targetProp, targetValue, finalResults) {

  function getObject(theObject) {
    let result = null;
    if (theObject instanceof Array) {
      for (let i = 0; i < theObject.length; i++) {
        getObject(theObject[i]);
      }
    }
    else {
      for (let prop in theObject) {
        if(theObject.hasOwnProperty(prop)){
          console.log(prop + ': ' + theObject[prop]);
          if (prop === targetProp) {
            console.log('--found id');
            if (theObject[prop] === targetValue) {
              console.log('----found porop', prop, ', ', theObject[prop]);
              finalResults.push(theObject);
            }
          }
          if (theObject[prop] instanceof Object || theObject[prop] instanceof Array){
            getObject(theObject[prop]);
          }
        }
      }
    }
  }

  getObject(obj);

}

Ce qu'il fait c'est qu'il trouve n'importe quel objet à l'intérieur de obj avec le nom et la valeur de la propriété correspondant à targetProp y targetValue et le poussera vers le finalResults l'array. Et voici le jsfiddle pour jouer autour : https://jsfiddle.net/alexQch/5u6q2ybc/

7voto

dominik791 Points 275

J'ai créé une bibliothèque dans ce but : https://github.com/dominik791/obj-traverse

Vous pouvez utiliser findFirst() méthode comme ceci :

var foundObject = findFirst(rootObject, 'options', { 'id': '1' });

Et maintenant foundObject stocke une référence à l'objet que vous recherchez.

5voto

Ali AlNoaimi Points 1152

Une autre solution récursive, qui fonctionne pour les tableaux/listes et les objets, ou un mélange des deux :

function deepSearchByKey(object, originalKey, matches = []) {

    if(object != null) {
        if(Array.isArray(object)) {
            for(let arrayItem of object) {
                deepSearchByKey(arrayItem, originalKey, matches);
            }
        } else if(typeof object == 'object') {

            for(let key of Object.keys(object)) {
                if(key == originalKey) {
                    matches.push(object);
                } else {
                    deepSearchByKey(object[key], originalKey, matches);
                }

            }

        }
    }

    return matches;
}

uso:

let result = deepSearchByKey(arrayOrObject, 'key'); // returns an array with the objects containing the key

4voto

Nassim Mesdour Points 114

Vous pouvez utiliser le javascript some à l'intérieur d'une fonction récursive. L'avantage de certaines est d'arrêter de boucler une fois que l'enfant est fondé. N'utilisez pas de map qui serait lente dans les grandes données.

const findChild = (array, id) => {
  let result;
  array.some(
    (child) =>
      (child.id === id && (result = child)) ||
      (result = findChild(child.options || [], id))
  );
  return result;
};

findNode(array, 1)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X