3 votes

Filtrer une structure de données compliquée

Avec une structure de données aléatoire (qui peut être n'importe quoi) :

const data = [
 {
  name: "John",
  age: 26,
  company: {
   name: "Some company",
   address: "Some address"
  }
 },{...}
];

Je voudrais pouvoir rechercher dans toutes les valeurs de l'objet et des sous-objets. Par exemple, si l'utilisateur tape "John", j'aimerais renvoyer tous les objets contenant "John", et si l'utilisateur cherche "Some company", j'aimerais renvoyer tous les objets contenant ces valeurs également.

J'ai pensé à aplatir la structure de chaque objet et à filtrer ensuite la liste originale, mais cela ne me semble pas correct. Avez-vous des suggestions ?

2voto

ibrahim mahrir Points 22237

Vous pouvez utiliser un chemin pour effectuer une recherche, par exemple :

search(data, "name", "John"); // search for object with names equal to "John"
search(data, "company.adress", "some adress"); // search for objects with company adresses equal to "some adress"
// ...

Le code pour cela sera :

function path2value(obj, path) {
    return path.split(".").reduce((o, p) => (o? o[p]: undefined), obj);
}

function search(arr, path, value) {
    return arr.filter(o => path2value(o, path) === value);
}

Exemple :

const data = [{
  name: "John",
  age: 26,
  company: {
    name: "Some company",
    address: "Some address"
  }
}, {
  name: "Ibrahim",
  age: 23,
  company: {
    name: "Some company",
    address: "Some address"
  }
}];

function path2value(obj, path) {
  return path.split(".").reduce((o, p) => (o ? o[p] : undefined), obj);
}

function search(arr, path, value) {
  return arr.filter(o => path2value(o, path) === value);
}

console.log(search(data, "name", "John"));
console.log(search(data, "company.name", "Some company"));

EDITAR:

Si vous ne voulez pas passer dans une path et vous voulez filtrer l'objet de manière récursive. Vous pouvez créer une fonction qui passe en revue toutes les valeurs de l'objet et de ses sous-objets et les passe à une callback (où vous pouvez spécifier si vous voulez ou non inclure cet objet), si la callback renvoie true, alors l'objet Root sera inclus dans le tableau de résultats, sinon il ne le sera pas. L'utilisation de cette fonction sera la suivante :

filterRecursive(data, value => value === "John"); // filter the objects by value equals to "John"
filterRecursive(data, value => typeof(value) === "number" && value > 20); // filter the objects by values that are numbers and greater than 20
filterRecursive(data, value => /^Some/.test(value)); // filter the objects with values that start with "Some"

la fonction serait :

function filterRecursive(arr, cb) {                                   // takes an array and a callback and recursively call the callback on each value in the object and sub object
    function hasIt(obj) {                                             // take an object and recurseively call the callback cb on its values and its subobjects values returning true if one of those values returned true, false if none of them returened true
        for(let key in obj) {                                         // for each key in the object
            if(obj.hasOwnProperty(key)) {                             // if the key is owned by this object
                if(Object.prototype.toString.call(obj[key]) === "[object Object]") {  // if the value on this key is another object...
                    if(hasIt(obj[key])) return true;                  // then call hasIt on it and if it returned true then return true and stop the search for this object
                }
                else if(cb(obj[key])) return true;                    // otherwise, if it's not an object, then pass it to the callback, if the callback returned true, then return true and stop the search
            }
        }
        return false;                                                 // return false if the recursive search failed
    }

    return arr.filter(o => hasIt(o)); // filter the root object by whether they have it or not (hasIt)
}

Exemple :

function filterRecursive(arr, cb) {
  function hasIt(obj) {
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (Object.prototype.toString.call(obj[key]) === "[object Object]") {
          if (hasIt(obj[key])) return true;
        } else if (cb(obj[key])) return true;
      }
    }
    return false;
  }

  return arr.filter(o => hasIt(o));
}

const data = [{
  name: "John",
  age: 26,
  company: {
    name: "Some company",
    address: "Some address"
  }
}, {
  name: "Ibrahim",
  age: 23,
  company: {
    name: "Some company",
    address: "Some address"
  }
}];

console.log(filterRecursive(data, v => v === "John"));
console.log(filterRecursive(data, v => /^Some/.test(v)));

2voto

Nina Scholz Points 17120

Vous pourriez utiliser une recherche récursive pour les objets avec Object.values .

var data = [{ name: "John", age: 26, company: { name: "Some company", address: "Some address" } }, { name: "Jane", age: 32, company: { name: "Cameo", address: "2nd Root Dr" } }],
    find = 'Cameo',
    result = data.filter(o => Object.values(o).some(function search(v) {
        return v && typeof v === 'object' ? Object.values(v).some(search) : v === find;
    }));

console.log(result);

.as-console-wrapper { max-height: 100% !important; top: 0; }

0voto

Christos Points 11296

Vous pourriez essayer quelque chose comme ça :

function getObjectValues(obj, values){
  for(var key in obj){
    let value = obj[key];
    if(typeof value === "object"){
      getObjectValues(value, values);
    } else {
        values.push(value)
    }
  }
  return values;
}

const data = [ 
 {
  name: "John",
  age: 26,
  company: {
   name: "Some company",
   address: "Some address"
  }
},
{
  name: "Bar",
  age: 27,
  company: {
   name: "Some company",
   address: "Some address"
  }
},
{
  name: "Foo",
  age: 28,
  company: {
   name: "Some company John",
   address: "Some address"
  }
}];

let filteredData = data.filter(function(obj){
    return getObjectValues(obj,[]).some(function(value){
        return value.toString()
                    .includes("John");
    });
});

console.log(filteredData);

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