Converter matriz em objeto


514

Qual é a melhor maneira de converter:

['a','b','c']

para:

{
  0: 'a',
  1: 'b',
  2: 'c'
}

3
Talvez o que ele precisa é de algum código de pato digitação não pensar que é uma ocorrência de Array
Pointy

6
Vale ressaltar que matrizes Javascript são objetos.
Spudley

Se alguém mais estiver procurando por uma solução Lodash, considere _.keyBy(anteriormente _.indexBy): lodash.com/docs#keyBy
2540625 18/02/02

Isso é um pouco confuso porque matrizes já são objetos, mas acho que o objetivo da pergunta é converter o objeto exótico da matriz em um objeto comum .
Oriol

1
Uma maneira simples de fazer isso com o Lodash é _.toPlainObject. Ex:var myObj = _.toPlainObject(myArr)
Julian Soro 04/11

Respostas:


473

O ECMAScript 6 apresenta o facilmente polifillable Object.assign:

O Object.assign()método é usado para copiar os valores de todas as propriedades próprias enumeráveis ​​de um ou mais objetos de origem para um objeto de destino. Ele retornará o objeto de destino.

Object.assign({}, ['a','b','c']); // {0:"a", 1:"b", 2:"c"}

A própria lengthpropriedade da matriz não é copiada porque não é enumerável.

Além disso, você pode usar a sintaxe de expansão ES6 para obter o mesmo resultado:

{ ...['a', 'b', 'c'] }

Apenas quero salientar - se você já tem um conjunto de propriedades ordenadas a partir do objeto original, utilizando a propagação do operador é o que vai transformar essa matriz diretamente em um novo objeto:{ ...[sortedArray]}
HappyHands31

Oriol, existe uma maneira de definir uma chave fixa em vez de 0 e 1?
Menai Ala Eddine

488

Com uma função como esta:

function toObject(arr) {
  var rv = {};
  for (var i = 0; i < arr.length; ++i)
    rv[i] = arr[i];
  return rv;
}

Sua matriz já é mais ou menos apenas um objeto, mas as matrizes têm algum comportamento "interessante" e especial em relação às propriedades com número inteiro. O texto acima fornecerá um objeto simples.

edite oh também você pode querer considerar "buracos" na matriz:

function toObject(arr) {
  var rv = {};
  for (var i = 0; i < arr.length; ++i)
    if (arr[i] !== undefined) rv[i] = arr[i];
  return rv;
}

Nos tempos de execução modernos do JavaScript, você pode usar o .reduce()método:

var obj = arr.reduce(function(acc, cur, i) {
  acc[i] = cur;
  return acc;
}, {});

Esse também evita "buracos" na matriz, porque é assim que .reduce()funciona.


2
@ m93a já é um objeto. No JavaScript, não há realmente sentido em criar uma instância Array ( []) se você não usar chaves de propriedade numéricas e a propriedade "length".
Pointy

14
maneira mais limpa de evitar a reatribuição de paramconst obj = arr.reduce((obj, cur, i) => { return { ...obj, [i]: cur }; }, {});
#

3
Seta + sintaxe de desestruturação sem retorno explícito:const obj = arr.reduce((obj, cur, i) => ({ ...obj, [i]: cur }), {});
Marc Scheib

2
@eugene_sunic de fato, mas essa abordagem não estava disponível quando eu respondi a essa em 2010 :)
Pointy

2
Como o @miro aponta, criar um novo objeto toda vez não é necessário e, de fato, é muito mais lento do que manipular o objeto inicial que foi criado. A execução de um teste JSPerf em uma matriz de 1000 elementos, criando um novo objeto toda vez é 1.000 vezes mais lenta que a mutação do objeto existente. jsperf.com/…
romellem 26/11/19

281

Você pode usar um acumulador aka reduce.

['a','b','c'].reduce(function(result, item, index, array) {
  result[index] = item; //a, b, c
  return result;
}, {}) //watch out the empty {}, which is passed as "result"

Passe um objeto vazio {}como ponto de partida; depois "aumente" esse objeto incrementalmente. No final das iterações, resultserá{"0": "a", "1": "b", "2": "c"}

Se sua matriz for um conjunto de objetos de pares de valores-chave:

[{ a: 1},{ b: 2},{ c: 3}].reduce(function(result, item) {
  var key = Object.keys(item)[0]; //first property: a, b, c
  result[key] = item[key];
  return result;
}, {});

vai produzir: {a: 1, b: 2, c: 3}

Por uma questão de integridade, reduceRightpermite iterar sua matriz na ordem inversa:

[{ a: 1},{ b: 2},{ c: 3}].reduceRight(/* same implementation as above */)

vai produzir: {c:3, b:2, a:1}

Seu acumulador pode ser de qualquer tipo para seu objetivo específico. Por exemplo, para trocar a chave e o valor do seu objeto em uma matriz, passe []:

[{ a: 1},{ b: 2},{ c: 3}].reduce(function(result, item, index) {
  var key = Object.keys(item)[0]; //first property: a, b, c
  var value = item[key];
  var obj = {};
  obj[value] = key;
  result.push(obj);
  return result;
}, []); //an empty array

vai produzir: [{1: "a"}, {2: "b"}, {3: "c"}]

Ao contrário map, reducenão pode ser usado como um mapeamento 1-1. Você tem controle total sobre os itens que deseja incluir ou excluir. Portanto, reducevocê pode conseguir o que filterfaz, o que torna reducemuito versátil:

[{ a: 1},{ b: 2},{ c: 3}].reduce(function(result, item, index) {
  if(index !== 0) { //skip the first item
    result.push(item);
  }
  return result;
}, []); //an empty array

vai produzir: [{2: "b"}, {3: "c"}]

Cuidado : reducee Object.keyfazem parte ECMA 5th edition; você deve fornecer um polyfill para navegadores que não os suportam (principalmente o IE8).

Veja uma implementação padrão do Mozilla .


1
Útil com a manutenção de uma loja redux quando você estiver usando um mapa de objetos e você precisa soltar uma das chaves
dhruvpatel

101

Se você estiver usando jquery:

$.extend({}, ['a', 'b', 'c']);

4
Estranho, se eu fornecer uma variável Array, ele coloca todos os caracteres em um objeto separado: 0: "a", 1: ",", 2: "b" ... Portanto, ignora as aspas, mas inclui as vírgulas. .
TrySpace

@ Max Eu acho que não existe esse comportamento. O objeto retornado é{0: 'a', 1: 'b', 2: 'c'} o resultado esperado.
ivkremer

3
Existe uma maneira de usar $ .extend enquanto informa as chaves de maneira não numérica, ou seja: fazendo cálculos nos itens da matriz?
Davi Lima

teste super impressionante e curto
Faisal Mehmood Awan

63

Para completar, o ECMAScript 2015 (ES6) está se espalhando. Exigirá um transpiler (Babel) ou um ambiente executando pelo menos ES6.

console.log(
   { ...['a', 'b', 'c'] }
)


2
Na verdade, isso também não está disponível nativamente no ES2015. É muito elegante no entanto.
Aluan Haddad

47

Eu provavelmente escreveria dessa maneira (já que muito raramente não terei a biblioteca underscorejs em mãos):

var _ = require('underscore');

var a = [ 'a', 'b', 'c' ];
var obj = _.extend({}, a);
console.log(obj);
// prints { '0': 'a', '1': 'b', '2': 'c' }

9
você votou negativamente na minha resposta, mas nenhum comentário? Minha resposta está correta e testada. Qual é a objeção?
Dave Dopson

14
Esta pergunta não possui uma marca de sublinhado e você também está assumindo o node.js ou uma biblioteca de solicitação.
precisa

10
sublinhado é bastante comum no cliente e no servidor. É assumido para o Backbone.js e é provavelmente a biblioteca de utilitários mais comum. Dito isto, incluí a linha de solicitação para deixar claro que estava usando uma biblioteca. Não há nenhuma 1-liner para descrever "underscore.js adicionar à sua página", de modo algum tradução é necessário para um ambiente de navegador
Dave Dopson

6
Ainda assim, se você estiver usando sublinhado, um simples obj=_.extend({},a);faria o trabalho. Além disso, se você estiver iterando através de matrizes, eu diria que _.eachseria mais apropriado do que _.map. Em suma, esta não é uma boa resposta em vários níveis.
precisa

4
As pessoas "você deve responder sem mencionar sublinhado ou pouco traço" são tão irritantes. Comparável a dizer que você deve responder perguntas sobre C ++ sem mencionar as bibliotecas padrão. Se sublinhado ou baixo traço não for uma opção, o OP deve mencionar isso.
Charlie Martin

26

Aqui está um método O (1) ES2015 apenas para ser completo.

var arr = [1, 2, 3, 4, 5]; // array, already an object
Object.setPrototypeOf(arr, Object.prototype); // now no longer an array, still an object

(1) De acordo com o MDN , alterar o [[Protótipo]] de um objeto é uma operação muito lenta. (2) Isso não remove a própria lengthpropriedade. (3) O objeto ainda é uma matriz Array.isArray(arr) === true,. (4) Comportamentos especiais de matriz não são removidos, por exemplo, arr.length = 0remove todos os índices. (5) Portanto, acho que Object.assigné muito melhor .
Oriol

1
O @Oriol mdn está errado, pelo menos na V8 (mas também em outros mecanismos), essa é uma operação bastante rápida nesse caso específico - já que os objetos têm um armazenamento numérico de qualquer maneira, isso basicamente altera dois ponteiros.
Benjamin Gruenbaum

Isso também pode ser usado pelo fato de ser aparentemente único entre as outras soluções rápidas, de preservar propriedades não indexadas ("próprias") na matriz (propriedades inteiras não positivas) ...
Brett Zamir

Mas hmm, Array.isArrayestá retornando truepara o "objeto" aqui, embora instanceof Arraynão ...
Brett Zamir

@BrettZamir que soa como um bug: D
Benjamin Gruenbaum

26

Surpreso por não ver -

console.log(
  Object.assign({}, ['a', 'b', 'c'])
)


Qualquer sugestão inteligente para criar { "first":"a", "second":"b","third":"c" }com as chaves sendo corrigidas - Estou procurando uma destruição
mplungjan

@mplungjan Eu sugiro usar reduzir em vez de atribuir nesse caso. Provavelmente, existe uma biblioteca que permite enumerar todos os ordinais, se necessário.
Wylliam Judd

Eu tive outro caso hoje. Acabei fazendo uma pergunta sobre isso: stackoverflow.com/questions/62197270/destruct-using-titles/…
mplungjan

23

podemos usar Object.assigne array.reducefuncionar para converter uma matriz em objeto.

var arr = [{a:{b:1}},{c:{d:2}}] 
var newObj = arr.reduce((a, b) => Object.assign(a, b), {})

console.log(newObj)


Era isso que eu estava procurando. Eu não precisava dos indeces, precisava transformar a matriz em pares de valores-chave retidos.
Mike K

18

Acabei usando o operador de propagação de objetos, pois faz parte do padrão ECMAScript 2015 (ES6).

const array = ['a', 'b', 'c'];
console.log({...array});
// it outputs {0:'a', 1:'b', 2:'c'}

Fez o violino a seguir como exemplo.


1
Não tenho certeza sobre o desempenho disso, mas dentre tantas conversões de matriz para objeto (desde que eu quero usar objetos para todos os meus códigos para padronizá-la), isso é provavelmente o mais fácil.
Alguém Especial

Como isso é melhor do que qualquer uma das respostas já existentes que deram a mesma solução?
Dan Dascalescu 03/04/19

17
Object.assign({}, ['one', 'two']); // {0: 'one', 1: 'two'}

A maneira mais fácil no JavaScript moderno é usar Object.assign()que não faz nada além de copiar a chave: valor de um objeto para outro. No nosso caso, Arraydoa propriedades para novas {}.


Como isso é melhor do que qualquer uma das respostas já existentes que deram a mesma solução?
Dan Dascalescu 03/04/19

Dan Dascalescu na época em que adicionei resposta, havia apenas uma resposta acima, O.assignmas faltava explicação. Hoje em dia desestruturação matriz em objecto é uma forma ( {...array})
Appeiron

14

Para o ES2016, espalhe o operador para objetos. Nota: Isso ocorre depois do ES6 e, portanto, o transpiler precisará ser ajustado.

const arr = ['a', 'b', 'c'];
const obj = {...arr}; // -> {0: "a", 1: "b", 2: "c"} 


A resposta do operador de spread já foi dada 2 anos antes .
Dan Dascalescu 03/04/19

11

Cinco anos depois, há um bom caminho :)

Object.assign foi introduzido no ECMAScript 2015.

Object.assign({}, ['a', 'b', 'c'])
// {'0':'a', '1':'b', '2':'c'}

10

Usando javascript#forEachum pode fazer isso

var result = {},
    attributes = ['a', 'b','c'];

attributes.forEach(function(prop,index) {
  result[index] = prop;
});

Com o ECMA6:

attributes.forEach((prop,index)=>result[index] = prop);

10

FWIW, uma outra abordagem recente é usar o novo Object.fromEntriesjuntamente com Object.entrieso seguinte:

const arr = ['a','b','c'];
arr[-2] = 'd';
arr.hello = 'e';
arr.length = 17;
const obj = Object.fromEntries(Object.entries(arr));

... o que permite evitar o armazenamento de itens esparsos da matriz como undefinedounull e preserva chaves não indexadas (por exemplo, número inteiro não positivo / não numérico).

Pode-se acrescentar arr.length, no entanto, que isso não está incluído:

obj.length = arr.length;


9

Se você estiver usando o ES6, poderá usar Object.assign e o operador spread

{ ...['a', 'b', 'c'] }

Se você tiver uma matriz aninhada como

var arr=[[1,2,3,4]]
Object.assign(...arr.map(d => ({[d[0]]: d[1]})))

1
Seus nomes de variáveis ​​não são apenas diferentes, mas seu exemplo não funcionará; a criação de um mapa a partir do construtor requer inicialmente 2d Matriz de valor-chave. new Map([['key1', 'value1'], ['key2', 'value2']]);
Shannon Hochkins

5

Rápido e sujo:

var obj = {},
  arr = ['a','b','c'],
  l = arr.length; 

while( l && (obj[--l] = arr.pop() ) ){};

Eu acho que você esqueceu de testar isso; produz {0:"c", 1:"b", 2:"a"}. Você quer em unshiftvez de popou (melhor) começa com i=arr.length-1e diminui.
Phrogz

sim .. apenas mudei, mas depois ficou menos interessante: /
Mic

Poderia até fazer l = arr.length, e então while (l && (obj[--l] = arr.pop())){}(eu percebo que isso é antigo, mas por que não simplificá-lo ainda mais)?
Qix - MONICA FOI ERRADA

2
@Qix, Nice encurtamento
Mic

4

Rápido e sujo # 2:

var i = 0
  , s = {}
  , a = ['A', 'B', 'C'];

while( a[i] ) { s[i] = a[i++] };

Por que você está usando notação de vírgula?
precisa saber é o seguinte

3
Preferência pessoal de ter a vírgula na próxima linha. Acho essa notação mais fácil de ler.
precisa saber é o seguinte

1
O loop será interrompido se a matriz contiver um valor falso. Você deve verificar em i < a.lengthvez de a[i].
Oriol

4

No Lodash 3.0.0, você pode usar _.toPlainObject

var obj = _.toPlainObject(['a', 'b', 'c']);
console.log(obj);
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>


3

Aqui está uma função recursiva que acabei de escrever. É simples e funciona bem.

// Convert array to object
var convArrToObj = function(array){
    var thisEleObj = new Object();
    if(typeof array == "object"){
        for(var i in array){
            var thisEle = convArrToObj(array[i]);
            thisEleObj[i] = thisEle;
        }
    }else {
        thisEleObj = array;
    }
    return thisEleObj;
}

Aqui está um exemplo ( jsFiddle ):

var array = new Array();
array.a = 123;
array.b = 234;
array.c = 345;
var array2 = new Array();
array2.a = 321;
array2.b = 432;
array2.c = 543;
var array3 = new Array();
array3.a = 132;
array3.b = 243;
array3.c = 354;
var array4 = new Array();
array4.a = 312;
array4.b = 423;
array4.c = 534;
var array5 = new Array();
array5.a = 112;
array5.b = 223;
array5.c = 334;

array.d = array2;
array4.d = array5;
array3.d = array4;
array.e = array3;


console.log(array);

// Convert array to object
var convArrToObj = function(array){
    var thisEleObj = new Object();
    if(typeof array == "object"){
        for(var i in array){
            var thisEle = convArrToObj(array[i]);
            thisEleObj[i] = thisEle;
        }
    }else {
        thisEleObj = array;
    }
    return thisEleObj;
}
console.log(convArrToObj(array));

Resultados: Matriz recursiva para objeto


Funciona muito bem. Obrigado
Hanmaslah

Isso deve ser mais alto, se você ['a' = '1', 'b' = '2', 'c' = '3']quiser e quiser, assim {a: 1, b: 2, c: 3}funciona perfeitamente.
Wanjia 23/07

3
.reduce((o,v,i)=>(o[i]=v,o), {})

[docs]

ou mais detalhado

var trAr2Obj = function (arr) {return arr.reduce((o,v,i)=>(o[i]=v,o), {});}

ou

var transposeAr2Obj = arr=>arr.reduce((o,v,i)=>(o[i]=v,o), {})

o mais curto com baunilha JS

JSON.stringify([["a", "X"], ["b", "Y"]].reduce((o,v,i)=>{return o[i]=v,o}, {}))
=> "{"0":["a","X"],"1":["b","Y"]}"

algum exemplo mais complexo

[["a", "X"], ["b", "Y"]].reduce((o,v,i)=>{return o[v[0]]=v.slice(1)[0],o}, {})
=> Object {a: "X", b: "Y"}

ainda mais curto (usando function(e) {console.log(e); return e;}=== (e)=>(console.log(e),e))

 nodejs
> [[1, 2, 3], [3,4,5]].reduce((o,v,i)=>(o[v[0]]=v.slice(1),o), {})
{ '1': [ 2, 3 ], '3': [ 4, 5 ] }

[/ docs]


Com o que você pretendia [/docs]? Seria mais útil tornar os trechos de código executáveis.
Dan Dascalescu 03/04/19

3

Eu faria isso simplesmente com Array.of(). A matriz de tem a capacidade de usar seu contexto como construtor.

NOTA 2 A função of é um método intencionalmente genérico de fábrica; não exige que esse valor seja o construtor Array. Portanto, ele pode ser transferido ou herdado por outros construtores que podem ser chamados com um único argumento numérico.

Portanto, podemos vincular Array.of()a uma função e gerar uma matriz como objeto.

function dummy(){};
var thingy = Array.of.apply(dummy,[1,2,3,4]);
console.log(thingy);

Utilizando Array.of() um pode-se até fazer subclassificação de array .


3

Se você pode usar Mapou Object.assign, é muito fácil.

Crie uma matriz:

const languages = ['css', 'javascript', 'php', 'html'];

A seguir, cria um objeto com o índice como chaves:

Object.assign({}, languages)

Replicar o mesmo que acima com o Maps

Converte em um objeto baseado em índice, {0 : 'css'}etc ...

const indexMap = new Map(languages.map((name, i) => [i, name] ));
indexMap.get(1) // javascript

Converter em um objeto baseado em valor, {css : 'css is great'}etc ...

const valueMap = new Map(languages.map(name => [name, `${name} is great!`] ));
valueMap.get('css') // css is great

3

Um método simples e atrevido de converter rapidamente uma matriz de itens em um objeto

function arrayToObject( srcArray ){
    return  JSON.parse( JSON.stringify( srcArray ) );
}

Então, usando-o assim ...

var p = [0,2,3,'pork','pie',6];
obj = new arrayToObject( p );
console.log( obj[3], obj[4] )
// expecting `pork pie`

Resultado:

pork pie

Verificando o tipo:

typeof obj
"object"

E as coisas não estariam completas se não houvesse um método de protótipo

Array.prototype.toObject =function(){
    return  JSON.parse( JSON.stringify( this ) );
}

Usando como:

var q = [0,2,3,'cheese','whizz',6];
obj = q.toObject();
console.log( obj[3], obj[4] )
// expecting `cheese whizz`

Resultado:

cheese whizz

* OBSERVE que não há rotina de nomeação; portanto, se você quiser ter nomes específicos, precisará continuar usando os métodos existentes abaixo.


Método mais antigo

Isso permite gerar a partir de uma matriz um objeto com as chaves definidas na ordem em que você as deseja.

Array.prototype.toObject = function(keys){
    var obj = {};
    var tmp = this; // we want the original array intact.
    if(keys.length == this.length){
        var c = this.length-1;
        while( c>=0 ){
            obj[ keys[ c ] ] = tmp[c];
            c--;
        }
    }
    return obj;
};

result = ["cheese","paint",14,8].toObject([0,"onion",4,99]);

console.log(">>> :" + result.onion); produzirá "paint", a função precisa ter matrizes de comprimento igual ou você obtém um objeto vazio.

Aqui está um método atualizado

Array.prototype.toObject = function(keys){
    var obj = {};
    if( keys.length == this.length)
        while( keys.length )
            obj[ keys.pop() ] = this[ keys.length ];
    return obj;
};

Isso destrói o conteúdo da matriz de chaves e, apesar do comentário interno, também a matriz de valores (seu conteúdo). O JavaScript funciona de maneira diferente do PHP, com o JavaScript atuando automaticamente por referência nas propriedades de um objeto / matriz.
Brett Zamir

Não, a rotina faz cópias, o original não é tocado.
Mark Giblin

Sim, o original é tocado. Veja jsfiddle.net/bRTv7 . Os comprimentos da matriz acabam sendo 0.
Brett Zamir 08/02

Ok, a versão editada com a qual eu mudei não destrói as matrizes, acha estranho que deveria ter feito isso.
Mark Giblin

1
Método atualizado que deve ser suportado em navegadores mais antigos, já que o JSON existe há mais tempo que a ECMA adicionou novos recursos de código
Mark Giblin

2

let i = 0;
let myArray = ["first", "second", "third", "fourth"];

const arrayToObject = (arr) =>
    Object.assign({}, ...arr.map(item => ({[i++]: item})));

console.log(arrayToObject(myArray));

Ou use

myArray = ["first", "second", "third", "fourth"]
console.log({...myArray})


2

ES5 - Solução:

Usando a função de protótipo Array 'push' e 'apply', você pode preencher o objeto com os elementos da matriz.

var arr = ['a','b','c'];
var obj = new Object();
Array.prototype.push.apply(obj, arr);
console.log(obj);    // { '0': 'a', '1': 'b', '2': 'c', length: 3 }
console.log(obj[2]); // c


E se eu quiser converter a{ name: a, div :b, salary:c}
Prashant Pimpale

2

Uma maneira mais flexível e suportada pelo navegador de fazer isso é usar um loop normal , algo como:

const arr = ['a', 'b', 'c'],
obj = {};

for (let i=0; i<arr.length; i++) {
   obj[i] = arr[i];
}

Mas também a maneira moderna pode estar usando o operador spread , como:

{...arr}

Ou Atribuição de objeto :

Object.assign({}, ['a', 'b', 'c']);

Ambos retornarão :

{0: "a", 1: "b", 2: "c"}

1

Você poderia usar uma função como esta:

var toObject = function(array) {
    var o = {};
    for (var property in array) {
        if (String(property >>> 0) == property && property >>> 0 != 0xffffffff) {
            o[i] = array[i];
        }
    }
    return o;
};

Este deve lidar com matrizes esparsas com mais eficiência.


1

Aqui está uma solução em coffeescript

arrayToObj = (arr) ->
  obj = {}
  for v,i in arr
    obj[i] = v if v?
  obj

7
O que é coffeescript? Estamos falando de JS! : D
m93a

2
É uma linguagem pouco que compila em JavaScript :)
David

6
Hmph, usa notação estranha. Eu gosto mais de JS simples.
M93a

2
@ David Você pode fazer o loop for inteiro em 1 linha para tornar a coisa toda apenas 3 linhas. :) Exemplo:obj[i] = v for v,i in arr when v?
XåpplI'-I0llwlg'I - 20/03
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.