web-dev-qa-db-fra.com

Bon moyen de chaîner les fonctions de filtrage en javascript

J'ai un grand tableau d'objets JSON que je dois filtrer en fonction de plusieurs entrées de sélection utilisateur. Actuellement, j'enchaîne les fonctions de filtrage, mais j'ai le sentiment que ce n'est probablement pas la manière la plus performante de le faire.

Actuellement, je fais ceci:

var filtered = data.filter(function(data) {
    return Conditional1
  })
  .filter(function(data) {
    return Conditional2
  })
  .filter(function(data) {
    return Conditional3
  }) etc...;

Bien que (je pense) à chaque itération, les "données" puissent être inférieures, je me demande si une meilleure pratique serait de faire quelque chose comme ceci:

var condition1 = Conditional1
var condition2 = Conditional2
var condition3 = Conditional3
etc...

var filtered = data.filter(function(data) {
  return condition1 && condition2 && condition3 && etc...
});

J'ai examiné plusieurs chaînes de fonctions d'ordre supérieur, en particulier la fonction de filtrage - mais je n'ai rien vu sur les meilleures pratiques (ou les mauvaises pratiques, et je n'ai pas chronométré et comparé les deux que j'ai suggérées).

Dans un cas d'utilisation avec un grand ensemble de données et de nombreux conditionnels qui seraient préférés (je pense qu'ils sont tous deux assez lisibles)?

Ou peut-être qu'il y a un moyen plus performant qui me manque (mais qui utilise toujours des fonctions d'ordre supérieur).

10
eaton9000

Stockez vos fonctions de filtrage dans un tableau et laissez array.reduce() parcourir chaque filtre, en l'appliquant aux données. Cela se fait au prix de leur exécution, même lorsqu'il n'y a plus de données à filtrer.

const data = [...]
const filters = [f1, f2, f3, ...]
const filteredData = filters.reduce((d, f) => d.filter(f) , data)

Une autre façon de le faire est d'utiliser array.every(). Cela prend l'approche inverse, en parcourant les données et en vérifiant si tous les filtres s'appliquent. array.every() retourne false dès qu'un élément retourne false.

const data = [...]
const filters = [f1, f2, f3, ...]
const filteredData = data.filter(v => filters.every(f => f(v)))

Les deux sont similaires à vos premier et deuxième échantillons, respectivement. La seule différence est qu'il ne code pas en dur les filtres ou les conditions.

16
Joseph

question interessante

data = new Array(111111).fill().map((a,n) => n);

const f1 = (a) => a % 2;
const f2 = (a) => a % 5;
const f3 = (a) => a > 347;
const filters = [f1, f2, f3];

// 1
t1 = performance.now();
res = data.filter(a=>a%2).filter(a=>a%5).filter(a=>a>347);
t2 = performance.now();
console.log("1) took " + (t2-t1) + " milliseconds.");
// 2
t1 = performance.now();
res = data.filter(a=>a%2 && a%5 && a>347);
t2 = performance.now();
console.log("2) took " + (t2-t1) + " milliseconds.");
// 3
t1 = performance.now();
res = filters.reduce((d, f) => d.filter(f) , data)
t2 = performance.now();
console.log("3) took " + (t2-t1) + " milliseconds.");
// 4
t1 = performance.now();
res = data.filter(v => filters.every(f => f(v)))
t2 = performance.now();
console.log("4) took " + (t2-t1) + " milliseconds.");

rappelez-vous également en for-loop et par exemple avec le cas de deux boucles une 3000 et une 7 puis: 3000x7> 7x3000 en mesure du temps.

5
nullqube

Les deux options ne sont pas exactement les mêmes, bien qu'elles puissent produire le même résultat

var filtered = data.filter(function(data) {
    return Conditional1
  })
  .filter(function(data) {
    return Conditional2
  })
  .filter(function(data) {
    return Conditional3
  }) etc...;

Cette option est meilleure si vous souhaitez vérifier les conditions indépendamment les unes des autres. Vous devez l'utiliser si vous avez besoin des données filtrées par condition1 avant de filtrer par condition2. Si vous voulez filtrer les éléments qui correspondent aux 3 conditions ou une combinaison de celles-ci, utilisez la seconde:

var condition1 = Conditional1
var condition2 = Conditional2
var condition3 = Conditional3
etc...

var filtered = data.filter(function(data) {
  return condition1 && condition2 && condition3 && etc...
});
2
SrThompson

Si vous considérez cela comme un problème d'optimisation "pour la boucle", vous pouvez voir que l'approche d'origine entraîne l'itération de la liste plusieurs fois.

Votre deuxième approche réduira les itérations à un seul passage.

Après cela, vous cherchez simplement la meilleure façon de décider rapidement si un élément réussit ou non.

0
theGleep