J'ai un objet multidimensionnel qui a une profondeur de 3 niveaux. J'essaie de savoir si l'objet de troisième niveau a une valeur donnée. Ce qui me vient à l'esprit, c'est de parcourir chaque niveau et de vérifier avec (Object.values(obj).indexOf('red') > -1) mais pour autant que je sache, le bouclage est un moyen lent.

Par exemple, dans l'objet ci-dessous, quel est le moyen le plus rapide de vérifier si l'une des valeurs les plus internes a une valeur red ou non, renvoyant un booléen?

myObj: {
   user1: {
      apples: {
        1: "red",
        2: "green",
        3: "black"
      },
      cherry: {
        2: "green"
        4: "dark"
      }
   },

   user2: {
     orange: {
        1: "orange"
     }
   }
}
2
senty 14 avril 2018 à 21:20

3 réponses

Meilleure réponse

Il s'agit d'une méthode récursive qui utilise {{X0 }} et {{X1 }} pour vérifier si une valeur existe dans un objet:

const obj = {"user1":{"apples":{"1":"red","2":"green","3":"black"},"cherry":{"2":"green","4":"dark"}},"user2":{"orange":{"1":"orange"}}};

const findValue = (o, val) => Object.values(o)
  .some((v) => v && typeof(v) === 'object' ? findValue(v, val) : (v === val));
  
console.log(findValue(obj, 'red'));
console.log(findValue(obj, 'gold'));
3
Ori Drori 14 avril 2018 à 18:29

Utilisez une fonction récursive profondeur d'abord pour parcourir les touches, puis au niveau le plus profond, retournez simplement true. Un "piège" consiste à s'assurer que les chaînes ne renvoient pas de chaînes de caractères uniques lors de l'itération, car cela récurrera simplement à l'infini.

function hasKey(object, depth = 0) {
  if (depth === 0) {
    return true;
  }

  for (const key in Object(object)) {
    const value = object[key];
    // prevent nested checks of characters in strings
    if (typeof value !== 'string' || value.length !== 1 || typeof object !== 'string') {
      if (hasKey(value, depth - 1)) {
        return true;
      }
    }
  }

  return false;
}

let myObj = {"user1":{"apples":{"1":"red","2":"green","3":"black"},"cherry":{"2":"green","4":"dark"}},"user2":{"orange":{"1":"orange"}}};

// has keys at depth 3
console.log(hasKey(myObj, 3));
// does not have keys at depth 4
console.log(hasKey(myObj, 4));

Bien que cette réponse puisse être plus longue en nombre de lignes, elle itère vraiment les clés à chaque profondeur plutôt que de mettre en mémoire tampon toutes les Object.values() dans un tableau à chaque profondeur, ce qui disqualifie techniquement les autres réponses de la possibilité de revendiquer une "profondeur -première "approche, car la mise en mémoire tampon provoque un comportement" en priorité ".

1
Patrick Roberts 14 avril 2018 à 18:45

Vous pouvez utiliser une recherche en profondeur d'abord et rechercher des objets imbriqués.

function contains(object, value) {
    return Object.values(object).some(
        v => v && typeof v === 'object'
            ? contains(v, value) :
            v === value
    );
}

var myObj = { user1: { apples: { 1: "red", 2: "green", 3: "black" }, cherry: { 2: "green", 4: "dark" } }, user2: { orange: { 1: "orange" } } };

console.log(contains(myObj, 'red'));
console.log(contains(myObj, 42));

Une autre solution pourrait être d'utiliser une pile et d'effectuer une recherche linéaire sans récusion.

Cela fonctionne comme une largeur-première-recherche.

function contains(object, value) {
    var stack = Object.values(object),
        v;

    while (stack.length) {
        v = stack.shift();
        if (v && typeof v === 'object') {
            stack.push(...Object.values(v));
            continue;
        }
        if (v === value) {
            return true;
        }
    }
    return false;
}

var myObj = { user1: { apples: { 1: "red", 2: "green", 3: "black" }, cherry: { 2: "green", 4: "dark" } }, user2: { orange: { 1: "orange" } } };

console.log(contains(myObj, 'red'));
console.log(contains(myObj, 42));
.as-console-wrapper { max-height: 100% !important; top: 0; }
3
Nina Scholz 14 avril 2018 à 19:00