Eu tenho uma matriz de objetos JavaScript com a seguinte estrutura:
objArray = [ { foo: 1, bar: 2}, { foo: 3, bar: 4}, { foo: 5, bar: 6} ];
Eu quero extrair um campo de cada objeto e obter uma matriz contendo os valores, por exemplo, campo foo
daria matriz [ 1, 3, 5 ]
.
Eu posso fazer isso com esta abordagem 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 uma maneira mais elegante ou idiomática de fazer isso, para que uma função de utilitário personalizada seja desnecessária?
Nota sobre duplicado sugerido , ele aborda como converter um único objeto em uma matriz.
var foos = objArray.pluck("foo");
.Array.prototype.map
função onde ela existeRespostas:
Aqui está uma maneira mais curta de alcançá-lo:
OU
Você também pode verificar
Array.prototype.map()
.fonte
Sim, mas depende de um recurso ES5 do JavaScript. Isso significa que não funcionará no IE8 ou mais antigo.
Nos intérpretes JS compatíveis com ES6, você pode usar uma função de seta por questões de brevidade:
Documentação Array.prototype.map
fonte
foo
?var result = objArray.map((a) => (a.foo));
var result = objArray.map(a => a.foo);
Confira a
_.pluck()
função de Lodash ou a_.pluck()
função de sublinhado . Ambos fazem exatamente o que você quer em uma única chamada de função!Atualização:
_.pluck()
foi removida a partir do Lodash v4.0.0 , em favor de_.map()
em combinação com algo semelhante à resposta de Niet ._.pluck()
ainda está disponível no Underscore .Atualização 2: como Mark aponta nos comentários , em algum lugar entre o Lodash v4 e o 4.3, foi adicionada uma nova função que fornece essa funcionalidade novamente.
_.property()
é uma função abreviada que retorna uma função para obter o valor de uma propriedade em um objeto.Além disso,
_.map()
agora permite que uma string seja passada como o segundo parâmetro, que é passado para_.property()
. Como resultado, as duas linhas a seguir são equivalentes ao exemplo de código acima do pré-Lodash 4._.property()
e, portanto_.map()
, também permite que você forneça uma string ou matriz separada por pontos para acessar subpropriedades:As duas
_.map()
chamadas no exemplo acima retornarão[5, 2, 9]
.Se você gosta um pouco mais de programação funcional, dê uma olhada na função Ramda
R.pluck()
, que seria algo como isto:fonte
_.property('foo')
( lodash.com/docs#property ) foi adicionado como uma abreviação defunction(o) { return o.foo; }
. Isto encurta o caso de uso de Lodashvar result = _.pluck(objArray, _.property('foo'));
Para maior conveniência, Lodash 4.3.0 do_.map()
método também permite uma forma abreviada usando_.property()
sob o capô, resultando emvar result = _.map(objArray, 'foo');
Falando apenas nas soluções JS, descobri que, por mais deselegante que seja, um
for
loop indexado simples tem mais desempenho do que suas alternativas.Extraindo propriedade única de uma matriz de 100000 elementos (via jsPerf)
Tradicional para loop 368 Ops / s
ES6 for..of loop 303 Ops / s
Array.prototype.map 19 Ops / s
TL; DR - .map () é lento, mas fique à vontade para usá-lo se achar que a legibilidade vale mais que o desempenho.
Edit # 2: 6/2019 - Link do jsPerf quebrado, removido.
fonte
É melhor usar algum tipo de bibliotecas como lodash ou sublinhado para garantir a navegação entre navegadores.
No Lodash, você pode obter valores de uma propriedade na matriz, seguindo o método
e em sublinhado
Ambos retornarão
fonte
Usando
Array.prototype.map
:Consulte o link acima para obter uma correção para os navegadores anteriores ao ES5.
fonte
No ES6, você pode fazer:
fonte
Embora
map
seja uma solução adequada para selecionar 'colunas' de uma lista de objetos, ela tem uma desvantagem. Se não for verificado explicitamente se as colunas existem ou não, ocorrerá um erro e (na melhor das hipóteses) fornecerá a vocêundefined
. Eu optaria por umareduce
solução, que pode simplesmente ignorar a propriedade ou até configurá-lo com um valor padrão.exemplo jsbin
Isso funcionaria mesmo se um dos itens da lista fornecida não for um objeto ou não contiver o campo.
Pode até ser mais flexível negociando um valor padrão, caso um item não seja um objeto ou não contenha o campo.
exemplo jsbin
Isso seria o mesmo com o mapa, pois o comprimento da matriz retornada seria o mesmo que a matriz fornecida. (Nesse caso, a
map
é um pouco mais barato que areduce
):exemplo jsbin
E há a solução mais flexível, que permite alternar entre os dois comportamentos simplesmente fornecendo um valor alternativo.
exemplo jsbin
Como os exemplos acima (esperançosamente) lançam alguma luz sobre o modo como isso funciona, vamos encurtar um pouco a
Array.concat
função utilizando a função.exemplo jsbin
fonte
Em geral, se você quiser extrapolar valores de objetos que estão dentro de uma matriz (como descrito na pergunta), poderá usar a redução, o mapa e a destruição de matriz.
ES6
O equivalente utilizando no circuito seria:
Saída produzida: ["word", "again", "some", "1", "2", "3"]
fonte
Depende da sua definição de "melhor".
As outras respostas apontam o uso do mapa, que é natural (especialmente para os homens acostumados ao estilo funcional) e conciso. Eu recomendo fortemente usá-lo (se você não se incomoda com os poucos caras do IE8-IT). Portanto, se "melhor" significa "mais conciso", "sustentável", "compreensível", então sim, é muito melhor.
Por outro lado, essa beleza não vem sem custos adicionais. Não sou muito fã de microbench, mas fiz um pequeno teste aqui . O resultado é previsível, a velha maneira feia parece ser mais rápida que a função de mapa. Portanto, se "melhor" significa "mais rápido", então não, fique com a moda antiga.
Novamente, este é apenas um microbench e, de maneira alguma, defendendo o uso de
map
, são apenas meus dois centavos :).fonte
map
é o caminho óbvio, de alguma forma eu apenas não consegui encontrá-lo no google (eu encontrei apenas o mapa do jquery, que não é relevante).Se você também deseja oferecer suporte a objetos do tipo matriz, use Array.from (ES2015):
A vantagem que ele tem sobre o método Array.prototype.map () é que a entrada também pode ser um conjunto :
fonte
Se você deseja vários valores no ES6 +, o seguinte funcionará
Isso funciona, pois
{foo, baz}
à esquerda está usando a destruição de objetos e no lado direito da seta é equivalente a{foo: foo, baz: baz}
devido aos literais de objetos aprimorados do ES6 .fonte
O mapa de funções é uma boa opção ao lidar com matrizes de objetos. Embora já existam várias boas respostas, o exemplo do uso de mapa com combinação com filtro pode ser útil.
Caso deseje excluir as propriedades cujos valores são indefinidos ou excluir apenas uma propriedade específica, você pode fazer o seguinte:
https://jsfiddle.net/ohea7mgk/
fonte
A resposta fornecida acima é boa para extrair uma única propriedade, e se você quiser extrair mais de uma propriedade da matriz de objetos. Aqui está a solução !! Nesse caso, podemos simplesmente usar _.pick (object, [caminhos])
Vamos supor que objArray tenha objetos com três propriedades, como abaixo
Agora queremos extrair a propriedade foo e bar de cada objeto e armazená-los em uma matriz separada. Primeiro, iteraremos os elementos da matriz usando o mapa e, em seguida, aplicaremos o método _.pick () do Lodash Library Standard.
Agora somos capazes de extrair as propriedades 'foo' e 'bar'.
var newArray = objArray.map((element)=>{ return _.pick(element, ['foo','bar'])}) console.log(newArray);
e o resultado seria [{foo: 1, bar: 2}, {foo: 3, bar: 4}, {foo: 5, bar: 6}]
desfrutar!!!
fonte
_.pick
vem? Não é uma função padrão.Se você tiver matrizes aninhadas, poderá fazê-lo funcionar assim:
fonte