Tengo una matriz de objetos JavaScript con la siguiente estructura:
objArray = [ { foo: 1, bar: 2}, { foo: 3, bar: 4}, { foo: 5, bar: 6} ];
Quiero extraer un campo de cada objeto y obtener una matriz que contenga los valores, por ejemplo, el campo foo
daría una matriz [ 1, 3, 5 ]
.
Puedo hacer esto con este enfoque trivial:
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 una forma más elegante o idiomática de hacer esto, de modo que una función de utilidad personalizada sea innecesaria?
Nota sobre el duplicado sugerido , cubre cómo convertir un solo objeto en una matriz.
var foos = objArray.pluck("foo");
.Array.prototype.map
función nativa donde existeRespuestas:
Aquí hay una forma más corta de lograrlo:
O
También puedes consultar
Array.prototype.map()
.fuente
Sí, pero se basa en una función ES5 de JavaScript. Esto significa que no funcionará en IE8 o versiones anteriores.
En los intérpretes JS compatibles con ES6, puede usar una función de flecha por brevedad:
Array.prototype.map documentation
fuente
foo
?var result = objArray.map((a) => (a.foo));
var result = objArray.map(a => a.foo);
Salida de Lodash
_.pluck()
función o de subrayado_.pluck()
función. ¡Ambos hacen exactamente lo que quieres en una sola llamada de función!Actualización:
_.pluck()
se ha eliminado a partir de Lodash v4.0.0 , a favor de_.map()
en combinación con algo similar a la respuesta de Niet ._.pluck()
todavía está disponible en Underscore .Actualización 2: Como Mark señala en los comentarios , en algún lugar entre Lodash v4 y 4.3, se ha agregado una nueva función que brinda esta funcionalidad nuevamente.
_.property()
es una función abreviada que devuelve una función para obtener el valor de una propiedad en un objeto.Además,
_.map()
ahora permite pasar una cadena como el segundo parámetro, que se pasa a_.property()
. Como resultado, las dos líneas siguientes son equivalentes al ejemplo de código anterior de pre-Lodash 4._.property()
y, por lo tanto_.map()
, también le permiten proporcionar una cadena o matriz separada por puntos para acceder a las subpropiedades:Ambas
_.map()
llamadas en el ejemplo anterior volverán[5, 2, 9]
.Si le gusta un poco más la programación funcional, eche un vistazo a la
R.pluck()
función de Ramda , que se vería así:fuente
_.property('foo')
( lodash.com/docs#property ) se agregó como abreviatura defunction(o) { return o.foo; }
. Esto acorta el caso de uso de Lodash avar result = _.pluck(objArray, _.property('foo'));
Para mayor comodidad, el_.map()
método de Lodash 4.3.0 también permite un uso abreviado_.property()
debajo del capó, lo que resulta envar result = _.map(objArray, 'foo');
Hablando de las soluciones solo para JS, descubrí que, por poco elegante que sea, un
for
bucle indexado simple es más eficaz que sus alternativas.Extracción de una propiedad individual de una matriz de 100000 elementos (a través de jsPerf)
Tradicional para loop 368 Ops / sec
ES6 para ... de bucle 303 Ops / sec
Array.prototype.map 19 Ops / sec
TL; DR - .map () es lento, pero siéntase libre de usarlo si cree que la legibilidad vale más que el rendimiento.
Edición n. ° 2: 6/2019: enlace jsPerf roto, eliminado.
fuente
Es mejor usar algún tipo de bibliotecas como lodash o guión bajo para asegurar el navegador cruzado.
En Lodash puede obtener valores de una propiedad en una matriz siguiendo el método
y en subrayado
Ambos volverán
fuente
Utilizando
Array.prototype.map
:Vea el enlace de arriba para ver una cuña para los navegadores anteriores a ES5.
fuente
En ES6, puedes hacer:
fuente
Si bien
map
es una solución adecuada para seleccionar 'columnas' de una lista de objetos, tiene un inconveniente. Si no se verifica explícitamente si las columnas existen o no, arrojará un error y (en el mejor de los casos) le proporcionaráundefined
. Optaría por unareduce
solución, que simplemente puede ignorar la propiedad o incluso configurarlo con un valor predeterminado.ejemplo de jsbin
Esto funcionaría incluso si uno de los elementos de la lista proporcionada no es un objeto o no contiene el campo.
Incluso puede hacerse más flexible negociando un valor predeterminado si un elemento no es un objeto o no contiene el campo.
ejemplo de jsbin
Esto sería lo mismo con el mapa, ya que la longitud de la matriz devuelta sería la misma que la matriz proporcionada. (En cuyo caso a
map
es un poco más barato que areduce
):ejemplo de jsbin
Y luego está la solución más flexible, una que le permite cambiar entre ambos comportamientos simplemente proporcionando un valor alternativo.
ejemplo de jsbin
Como los ejemplos anteriores (con suerte) arrojan algo de luz sobre cómo funciona esto, acortemos un poco la
Array.concat
función utilizando la función.ejemplo de jsbin
fuente
En general, si desea extrapolar los valores de los objetos que están dentro de una matriz (como se describe en la pregunta), puede utilizar la reducción, el mapeo y la desestructuración de la matriz.
ES6
El equivalente para for in loop sería:
Salida producida: ["palabra", "otra vez", "algo", "1", "2", "3"]
fuente
Depende de su definición de "mejor".
Las otras respuestas señalan el uso del mapa, que es natural (especialmente para los hombres acostumbrados al estilo funcional) y conciso. Recomiendo encarecidamente usarlo (si no te molestas con los pocos chicos de IE8-IT). Entonces, si "mejor" significa "más conciso", "mantenible", "comprensible", entonces sí, es mucho mejor.
Por otro lado, esta belleza no viene sin costos adicionales. No soy un gran admirador del microbench, pero he realizado una pequeña prueba aquí . El resultado es predecible, la antigua forma fea parece ser más rápida que la función de mapa. Entonces, si "mejor" significa "más rápido", entonces no, quédese con la moda de la vieja escuela.
Nuevamente, esto es solo un microbench y de ninguna manera aboga contra el uso de
map
, solo son mis dos centavos :)fuente
map
es el camino obvio a seguir, de alguna manera no pude encontrarlo con Google (encontré solo el mapa de jquery, que no es relevante).Si también desea admitir objetos tipo matriz, use Array.from (ES2015):
La ventaja que tiene sobre el método Array.prototype.map () es que la entrada también puede ser un conjunto :
fuente
Si desea valores múltiples en ES6 +, lo siguiente funcionará
Esto funciona
{foo, baz}
de la izquierda está utilizando destructoring objeto y en el lado derecho de la flecha es equivalente a{foo: foo, baz: baz}
Debido a objetos literales mejoradas de ES6 .fuente
El mapa de funciones es una buena opción cuando se trata de matrices de objetos. Aunque ya se han publicado una serie de buenas respuestas, el ejemplo del uso del mapa con combinación con filtro podría ser útil.
En caso de que desee excluir las propiedades cuyos valores no están definidos o excluir solo una propiedad específica, puede hacer lo siguiente:
https://jsfiddle.net/ohea7mgk/
fuente
La respuesta proporcionada anteriormente es buena para extraer una sola propiedad, y si desea extraer más de una propiedad de una matriz de objetos. ¡Aquí está la solución! En ese caso, simplemente podemos usar _.pick (objeto, [rutas])
Supongamos que objArray tiene objetos con tres propiedades como a continuación
Ahora queremos extraer la propiedad foo y bar de cada objeto y almacenarlos en una matriz separada. Primero iteraremos los elementos de la matriz utilizando el mapa y luego aplicaremos el método Lodash Library Standard _.pick ().
Ahora podemos extraer la propiedad 'foo' y 'bar'.
var newArray = objArray.map((element)=>{ return _.pick(element, ['foo','bar'])}) console.log(newArray);
y el resultado sería [{foo: 1, bar: 2}, {foo: 3, bar: 4}, {foo: 5, bar: 6}]
¡¡¡disfrutar!!!
fuente
_.pick
viene No es una función estándar.Si tiene matrices anidadas, puede hacer que funcione así:
fuente