Question À partir d'un tableau d'objets, extrayez la valeur d'une propriété en tant que tableau


J'ai un tableau d'objets JavaScript avec la structure suivante:

objArray = [ { foo: 1, bar: 2}, { foo: 3, bar: 4}, { foo: 5, bar: 6} ];

Je veux extraire un tableau contenant les valeurs de la clé foo, résultant en une valeur de [ 1, 3, 5 ].

J'ai accompli ceci avec l'approche triviale, comme suit:

function getFields(input, field) {
    var output = [];
    for (var i=0; i < input.length ; ++i)
        output.push(input[i][field]);
    return output;
}

var result = getFields(objArray, "foo"); // returns [ 1, 3, 5 ]

Existe-t-il une méthode plus élégante et plus performante?


Notez à propos de suggestion de doublon, cette question demande comment convertir un objet à un tableau, cette question demande comment extraire une propriété unique de un tableau d'objets.


443
2017-10-25 13:13


origine


Réponses:


voici un moyen plus court d'y parvenir

var result = objArray.map(a => a.foo);

360
2017-10-11 17:33



Oui, mais il repose sur une fonctionnalité ES5 de JavaScript. Cela signifie qu'il ne fonctionnera pas dans IE8 ou plus.

var result = objArray.map(function(a) {return a.foo;});

Sur les interpréteurs JS compatibles ES6, vous pouvez utiliser un fonction de flèche pour la brièveté:

var result = objArray.map(a => a.foo);

Documentation


507
2017-10-25 13:14



Check-out Lodash's _.pluck() fonction ou Underscore _.pluck() fonction. Les deux font exactement ce que vous voulez dans un appel de fonction unique!

var result = _.pluck(objArray, 'foo');

Mettre à jour:  _.pluck() a été supprimé à partir de Lodash v4.0.0, en faveur de _.map() en combinaison avec quelque chose de similaire à La réponse de Niet. _.pluck() est toujours disponible dans Underscore.

Mise à jour 2: Comme Mark le souligne dans les commentaires, quelque part entre Lodash v4 et 4.3, une nouvelle fonction a été ajoutée qui fournit cette fonctionnalité à nouveau. _.property() est une fonction abrégée qui retourne une fonction pour obtenir la valeur d'une propriété dans un objet.

Aditionellement, _.map() permet maintenant qu'une chaîne soit transmise en tant que second paramètre, qui est passé dans _.property(). Par conséquent, les deux lignes suivantes sont équivalentes à l'exemple de code ci-dessus de pré-Lodash 4.

var result = _.map(objArray, 'foo');
var result = _.map(objArray, _.property('foo'));

_.property(), et donc _.map(), vous permettent également de fournir une chaîne ou un tableau séparé par des points afin d'accéder aux sous-propriétés:

var objArray = [
    {
        someProperty: { aNumber: 5 }
    },
    {
        someProperty: { aNumber: 2 }
    },
    {
        someProperty: { aNumber: 9 }
    }
];
var result = _.map(objArray, _.property('someProperty.aNumber'));
var result = _.map(objArray, _.property(['someProperty', 'aNumber']));

Tous les deux _.map() les appels dans l'exemple ci-dessus retourneront [5, 2, 9].

Si vous êtes un peu plus dans la programmation fonctionnelle, jetez un coup d’œil à Ramda  R.pluck() fonction, qui ressemblerait à ceci:

var result = R.pluck('foo')(objArray);  // or just R.pluck('foo', objArray)

36
2018-04-16 03:16



En ce qui concerne les solutions JS only, j’ai trouvé que, aussi peu for La boucle est plus performante que ses alternatives.

https://jsperf.com/extract-prop-from-object-array/

Extraction d'une propriété unique à partir d'un tableau d'éléments 100000

Traditionnel pour la boucle 368 Ops / sec

var vals=[];
for(var i=0;i<testArray.length;i++){
   vals.push(testArray[i].val);
}

ES6 pour..de boucle 303 Ops / sec

var vals=[];
for(var item of testArray){
   vals.push(item.val); 
}

Array.prototype.map 19 Ops / s

var vals = testArray.map(function(a) {return a.val;});

Edit: Ops / s mis à jour 10/2017. TL; DR - .map () est lent. Mais parfois, la lisibilité vaut plus que la performance.


24
2018-02-06 02:13



En utilisant Array.prototype.map:

function getFields(input, field) {
    return input.map(function(o) {
        return o[field];
    });
}

Voir le lien ci-dessus pour une cale pour les navigateurs pré-ES5.


14
2017-10-25 13:15



Il est préférable d'utiliser un certain type de bibliothèques comme lodash ou underscore pour l'assurance croisée du navigateur.

Dans lodash, vous pouvez obtenir les valeurs d'une propriété dans un tableau en suivant la méthode

_.map(objArray,"foo")

et en soulignant

_.pluck(objArray,"foo")

les deux reviendront [1, 3, 5]


7
2018-02-09 04:00



Tandis que map est une solution appropriée pour sélectionner des «colonnes» à partir d'une liste d'objets, il a un inconvénient. Si ce n'est pas explicitement vérifié si les colonnes existent ou non, cela générera une erreur et (au mieux) vous fournira undefined. J'opterais pour un reduce solution, qui peut simplement ignorer la propriété ou même vous définir avec une valeur par défaut.

function getFields(list, field) {
    //  reduce the provided list to an array only containing the requested field
    return list.reduce(function(carry, item) {
        //  check if the item is actually an object and does contain the field
        if (typeof item === 'object' && field in item) {
            carry.push(item[field]);
        }

        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

exemple jsbin

Cela fonctionnerait même si l'un des éléments de la liste fournie n'est pas un objet ou ne contient pas le champ.

Cela peut même être rendu plus flexible en négociant une valeur par défaut si un élément n'est pas un objet ou ne contient pas le champ.

function getFields(list, field, otherwise) {
    //  reduce the provided list to an array containing either the requested field or the alternative value
    return list.reduce(function(carry, item) {
        //  If item is an object and contains the field, add its value and the value of otherwise if not
        carry.push(typeof item === 'object' && field in item ? item[field] : otherwise);

        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

exemple jsbin

Ce serait la même chose avec map, car la longueur du tableau renvoyé serait la même que celle du tableau fourni. (Dans ce cas, un map est légèrement moins cher qu'un reduce):

function getFields(list, field, otherwise) {
    //  map the provided list to an array containing either the requested field or the alternative value
    return list.map(function(item) {
        //  If item is an object and contains the field, add its value and the value of otherwise if not
        return typeof item === 'object' && field in item ? item[field] : otherwise;
    }, []);
}

exemple jsbin

Et puis il y a la solution la plus flexible, celle qui vous permet de basculer entre les deux comportements en fournissant simplement une valeur alternative.

function getFields(list, field, otherwise) {
    //  determine once whether or not to use the 'otherwise'
    var alt = typeof otherwise !== 'undefined';

    //  reduce the provided list to an array only containing the requested field
    return list.reduce(function(carry, item) {
        //  If item is an object and contains the field, add its value and the value of 'otherwise' if it was provided
        if (typeof item === 'object' && field in item) {
            carry.push(item[field]);
        }
        else if (alt) {
            carry.push(otherwise);
        }

        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

exemple jsbin

Comme les exemples ci-dessus (espérons-le) nous éclairent sur la manière dont cela fonctionne, raccourcissons un peu la fonction en utilisant le Array.concat fonction.

function getFields(list, field, otherwise) {
    var alt = typeof otherwise !== 'undefined';

    return list.reduce(function(carry, item) {
        return carry.concat(typeof item === 'object' && field in item ? item[field] : (alt ? otherwise : []));
    }, []);
}

exemple jsbin


3
2017-11-19 10:02