126 votes

Suppression d'éléments avec Array.map en JavaScript

J'aimerais filtrer un tableau d'éléments en utilisant la fonction map() fonction. Voici un extrait de code :

var filteredItems = items.map(function(item)
{
    if( ...some condition... )
    {
        return item;
    }
});

Le problème est que les éléments filtrés utilisent encore de l'espace dans le tableau et j'aimerais les supprimer complètement.

Une idée ?

EDIT : Merci, j'avais oublié filter() Ce que je voulais, c'est en fait un filter() puis un map() .

EDIT2 : Merci de l'avoir signalé map() y filter() ne sont pas implémentés dans tous les navigateurs, bien que mon code spécifique ne soit pas destiné à être exécuté dans un navigateur.

131voto

olliej Points 16255

Vous devez utiliser le filter plutôt que map, à moins que vous ne souhaitiez modifier les éléments du tableau, en plus du filtrage.

eg.

var filteredItems = items.filter(function(item)
{
    return ...some condition...;
});

[Edit : Of course you could always do sourceArray.filter(...).map(...) pour filtrer et muter]

61voto

Kyle Baker Points 1420

Inspiré par la rédaction de cette réponse, j'ai fini par développer et rédiger un article de blog qui aborde ce sujet en détail. Je recommande vérifier cela si vous voulez développer une compréhension plus profonde de la façon de penser ce problème - j'essaie de l'expliquer morceau par morceau, et je donne également une comparaison JSperf à la fin, en passant en revue les considérations de vitesse.

Ceci étant dit, **La version abrégée est la suivante :

Pour réaliser ce que vous demandez (filtrage et mappage en un seul appel de fonction), vous devez utiliser Array.reduce() **.

Toutefois, le plus lisible et (moins important) généralement beaucoup plus rapide 2 est d'utiliser simplement le filtre et la carte, enchaînés l'un à l'autre :

[1,2,3].filter(num => num > 2).map(num => num * 2)

Ce qui suit est une description de la façon dont Array.reduce() et comment il peut être utilisé pour réaliser un filtre et une carte en une seule itération. Encore une fois, si cela vous semble trop condensé, je vous recommande vivement de consulter l'article du blog dont le lien figure ci-dessus, qui constitue une introduction beaucoup plus conviviale, avec des exemples et une progression clairs.


Vous donnez à reduce un argument qui est une fonction (généralement anonyme).

Cette fonction anonyme prend deux paramètres, dont l'un (comme les fonctions anonymes passées à map/filter/forEach) est l'itération à opérer. Il existe cependant un autre argument pour la fonction anonyme passée à reduce, que ces fonctions n'acceptent pas, à savoir la valeur qui sera transmise entre les appels de fonction, souvent désignée par le terme "valeur". mémo .

Notez que si Array.filter() ne prend qu'un seul argument (une fonction), Array.reduce() prend également un deuxième argument important (bien qu'optionnel) : une valeur initiale pour "memo" qui sera transmise à cette fonction anonyme en tant que premier argument, et qui pourra ensuite être modifiée et transmise entre les appels de la fonction. (S'il n'est pas fourni, 'memo' dans le premier appel de la fonction anonyme sera par défaut le premier itéré, et l'argument 'itéré' sera en fait la deuxième valeur du tableau).

Dans notre cas, nous passerons un tableau vide pour commencer, puis nous choisirons d'injecter ou non notre itération dans notre tableau en fonction de notre fonction - c'est le processus de filtrage.

Enfin, nous renverrons notre "tableau en cours" à chaque appel de fonction anonyme, et reduce prendra cette valeur de retour et la transmettra en tant qu'argument (appelé memo) à son prochain appel de fonction.

Cela permet au filtre et à la carte d'être exécutés en une seule itération, réduisant ainsi de moitié le nombre d'itérations nécessaires - il faut cependant faire deux fois plus de travail à chaque itération, donc rien n'est vraiment économisé en dehors des appels de fonction, qui ne sont pas si coûteux en javascript.

Pour une explication plus complète, voir MDN (ou à mon post référencé au début de cette réponse).

Exemple de base d'un appel à la réduction :

let array = [1,2,3];
const initialMemo = [];

array = array.reduce((memo, iteratee) => {
    // if condition is our filter
    if (iteratee > 1) {
        // what happens inside the filter is the map
        memo.push(iteratee * 2); 
    }

    // this return value will be passed in as the 'memo' argument
    // to the next call of this function, and this function will have
    // every element passed into it at some point.
    return memo; 
}, initialMemo)

console.log(array) // [4,6], equivalent to [(2 * 2), (3 * 2)]

version plus succincte :

[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])

Remarquez que le premier itéré n'était pas supérieur à un et a donc été filtré. Notez également l'initialMemo, nommé juste pour rendre son existence claire et attirer l'attention sur lui. Une fois de plus, il est transmis en tant que "memo" au premier appel de fonction anonyme, puis la valeur renvoyée par la fonction anonyme est transmise en tant qu'argument "memo" à la fonction suivante.

Un autre exemple de cas d'utilisation classique de memo serait de renvoyer le plus petit ou le plus grand nombre d'un tableau. Exemple de cas d'utilisation :

[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
// ^this would return the largest number in the list.

Un exemple de la manière d'écrire votre propre fonction de réduction (je trouve que cela aide souvent à comprendre des fonctions comme celles-ci) :

test_arr = [];

// we accept an anonymous function, and an optional 'initial memo' value.
test_arr.my_reducer = function(reduceFunc, initialMemo) {
    // if we did not pass in a second argument, then our first memo value 
    // will be whatever is in index zero. (Otherwise, it will 
    // be that second argument.)
    const initialMemoIsIndexZero = arguments.length < 2;

    // here we use that logic to set the memo value accordingly.
    let memo = initialMemoIsIndexZero ? this[0] : initialMemo;

    // here we use that same boolean to decide whether the first
    // value we pass in as iteratee is either the first or second
    // element
    const initialIteratee = initialMemoIsIndexZero ? 1 : 0;

    for (var i = initialIteratee; i < this.length; i++) {
        // memo is either the argument passed in above, or the 
        // first item in the list. initialIteratee is either the
        // first item in the list, or the second item in the list.
           memo = reduceFunc(memo, this[i]);
        // or, more technically complete, give access to base array
        // and index to the reducer as well:
        // memo = reduceFunc(memo, this[i], i, this);
    }

    // after we've compressed the array into a single value,
    // we return it.
    return memo;
}

L'implémentation réelle permet d'accéder à des éléments tels que l'index, par exemple, mais j'espère que cela vous aidera à vous faire une idée simple de l'essentiel.

13voto

Patrick Points 20392

Ce n'est pas ce que fait la carte. Vous voulez vraiment Array.filter . Ou si vous voulez vraiment supprimer les éléments de la liste originale, vous devrez le faire impérativement avec une boucle for.

6voto

vsync Points 11280

Tableau Méthode de filtrage

var arr = [1, 2, 3]

// ES5 syntax
arr = arr.filter(function(item){ return item != 3 })

// ES2015 syntax
arr = arr.filter(item => item != 3)

console.log( arr )

1voto

ggasp Points 608

Il convient toutefois de noter que le Array.filter n'est pas supporté par tous les navigateurs, vous devez donc le prototyper :

//This prototype is provided by the Mozilla foundation and
//is distributed under the MIT license.
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license

if (!Array.prototype.filter)
{
    Array.prototype.filter = function(fun /*, thisp*/)
    {
        var len = this.length;

        if (typeof fun != "function")
            throw new TypeError();

        var res = new Array();
        var thisp = arguments[1];

        for (var i = 0; i < len; i++)
        {
            if (i in this)
            {
                var val = this[i]; // in case fun mutates this

                if (fun.call(thisp, val, i, this))
                   res.push(val);
            }
        }

        return res;
    };
}

Ce faisant, vous pouvez prototyper toutes les méthodes dont vous avez besoin.

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