web-dev-qa-db-fra.com

Utiliser une carte de matrice pour filtrer les résultats avec si conditionnel

J'essaie d'utiliser une carte matricielle pour filtrer un objet un peu plus loin pour le préparer à l'envoi au serveur pour qu'il enregistre. Je peux filtrer sur 1 valeur de clé, ce qui est excellent, mais je veux aller encore plus loin et les comparer à un booléen à l'intérieur.

Donc, maintenant c'est ce que j'ai -

$scope.appIds = $scope.applicationsHere.map( function(obj){
        if(obj.selected == true){
            return obj.id;
        }
    });

Cela fonctionne très bien pour extraire les identifiants, mais je ne veux pas les pousser dans ce nouveau tableau s'ils ont leur valeur sélectionnée == false, alors je mets une conditionnelle pour filtrer davantage. Cela fonctionne un peu, je reçois un tableau d'identifiants, mais les identifiants qui ont .selected == false sont toujours dans le tableau, avec juste la valeur null. Donc, si j'ai 4 objets dans l'objet et que 2 d'entre eux sont faux, cela ressemble à ceci -

 appIds = {id1, id2, null, null};

Ma question est la suivante: existe-t-il un moyen de le faire sans que les valeurs nulles soient incluses? Merci d'avoir lu!

30
ajmajmajma

Vous recherchez la fonction .filter():

  $scope.appIds = $scope.applicationsHere.filter(function(obj) {
    return obj.selected;
  });

Cela produira un tableau qui ne contient que les objets dont la propriété "sélectionnée" est true (ou vérité).

éditer désolé je prenais un café et j'ai raté les commentaires - oui, comme l'a noté jAndy dans un commentaire, filtrer puis extraire simplement le "id" "valeurs, ce serait:

  $scope.appIds = $scope.applicationsHere.filter(function(obj) {
    return obj.selected;
  }).map(function(obj) { return obj.id; });

Certaines bibliothèques fonctionnelles (comme Functional , qui à mon avis ne suscite pas assez d'amour) ont une fonction .pluck() pour extraire les valeurs de propriétés d'une liste d'objets, mais le JavaScript natif a un joli ensemble maigre de ces outils.

64
Pointy

Vous devez utiliser Array.prototype.reduce pour le faire. J'ai fait un petit test de performance JS pour vérifier que cela est plus performant que de faire un .filter + .map.

$scope.appIds = $scope.applicationsHere.reduce(function(ids, obj){
    if(obj.selected === true){
        ids.Push(obj.id);
    }
    return ids;
}, []);

Juste par souci de clarté, voici l’échantillon .reduce J'ai utilisé le test JSPerf:

  var things = [
    {id: 1, selected: true},
    {id: 2, selected: true},
    {id: 3, selected: true},
    {id: 4, selected: true},
    {id: 5, selected: false},
    {id: 6, selected: true},
    {id: 7, selected: false},
    {id: 8, selected: true},
    {id: 9, selected: false},
    {id: 10, selected: true},
  ];
  
        
var ids = things.reduce((ids, thing) => {
  if (thing.selected) {
    ids.Push(thing.id);
  }
  return ids;
}, []);

console.log(ids)

EDIT 1

Remarque: à compter du 2/2018 Réduire + Push est le plus rapide en Chrome et Edge, mais plus lent que Filtre + Carte dans Firefox

12
Justin L.

Voici quelques informations si quelqu'un en parle en 2019.

Je pense que réduire vs carte + filtre pourrait être quelque peu dépendant de ce que vous devez parcourir en boucle. Pas sûr, mais réduire semble être plus lent.

Une chose est sûre: si vous souhaitez améliorer les performances, la manière dont vous écrivez le code est extrêmement importante!

Ici, un test de performance JS qui montre les énormes améliorations apportées lors de la saisie complète du code plutôt que de rechercher des valeurs "falsey" (par exemple, if (string) {...}) ou de renvoyer des valeurs "falsey" avec un booléen devrait.

J'espère que cela aide quelqu'un

1
Laurynas