Convertir matriz en objeto


514

¿Cuál es la mejor manera de convertir:

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

a:

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

3
Tal vez lo que necesita es que algún código de escritura de pato no piense que es una instancia de Array
Pointy, el

66
Vale la pena señalar que las matrices Javascript son objetos.
Spudley

Si alguien más está buscando una solución de Lodash, considere _.keyBy(anteriormente _.indexBy): lodash.com/docs#keyBy
2540625

Esto es un poco confuso porque las matrices ya son objetos, pero supongo que el punto de la pregunta es convertir la matriz de objetos exóticos en un objeto ordinario .
Oriol

1
Una forma simple de hacer esto con Lodash es _.toPlainObject. Ej:var myObj = _.toPlainObject(myArr)
Julian Soro

Respuestas:


473

ECMAScript 6 presenta lo fácilmente polifilable Object.assign:

El Object.assign()método se utiliza para copiar los valores de todas las propiedades propias enumerables de uno o más objetos de origen a un objeto de destino. Devolverá el objeto de destino.

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

El propio length propiedad de la matriz no se copia porque no es enumerable.

Además, puede usar la sintaxis extendida ES6 para lograr el mismo resultado:

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

Solo quiero señalar: si ya tiene una matriz de propiedades ordenadas del objeto original, usar el operador de propagación es lo que convertirá esa matriz directamente en un nuevo objeto:{ ...[sortedArray]}
HappyHands31

Oriol, ¿hay alguna forma de establecer una clave fija en lugar de 0 y 1?
Menai Ala Eddine

488

Con una función como esta:

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

Su matriz ya es más o menos un simple objeto, pero las matrices tienen un comportamiento "interesante" y especial con respecto a las propiedades con nombre entero. Lo anterior le dará un objeto simple.

editar oh también es posible que desee tener en cuenta los "agujeros" en la matriz:

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

En tiempos de ejecución de JavaScript modernos, puede usar el .reduce()método:

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

Ese también evita los "agujeros" en la matriz, porque así es como .reduce()funciona.


2
@ m93a ya es un objeto. En JavaScript, realmente no tiene sentido crear una instancia de Array ( []) si no va a utilizar claves de propiedad numéricas y la propiedad "length".
Puntiagudo

14
forma más limpia de evitar la reasignación de paramconst obj = arr.reduce((obj, cur, i) => { return { ...obj, [i]: cur }; }, {});
huygn

3
Flecha + sintaxis de desestructuración sin retorno explícito:const obj = arr.reduce((obj, cur, i) => ({ ...obj, [i]: cur }), {});
Marc Scheib

2
@eugene_sunic de hecho, pero ese enfoque no estaba disponible cuando respondí esto en 2010 :)
Pointy

2
Como señala @miro, crear un nuevo objeto cada vez no es necesario, y de hecho es mucho más lento que manipular el objeto inicial que se creó. Ejecutar una prueba JSPerf en una matriz de 1000 elementos, crear un nuevo objeto cada vez es 1,000 veces más lento que mutar el objeto existente. jsperf.com/…
romellem

281

Podrías usar un 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"

Pase un objeto vacío {}como punto de partida; luego "aumenta" ese objeto de forma incremental. Al final de las iteraciones, resultserá{"0": "a", "1": "b", "2": "c"}

Si su matriz es un conjunto de objetos de pares clave-valor:

[{ 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;
}, {});

Producirá: {a: 1, b: 2, c: 3}

En aras de la integridad, le reduceRightpermite iterar sobre su matriz en orden inverso:

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

Producirá: {c:3, b:2, a:1}

Su acumulador puede ser de cualquier tipo para su propósito específico. Por ejemplo, para intercambiar la clave y el valor de su objeto en una matriz, pase []:

[{ 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

Producirá: [{1: "a"}, {2: "b"}, {3: "c"}]

A diferencia map, reduceno se puede usar como un mapeo 1-1. Usted tiene control total sobre los elementos que desea incluir o excluir. Por lo tanto, le reducepermite lograr lo que filterhace, lo que lo hace reducemuy 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

Producirá: [{2: "b"}, {3: "c"}]

Precaución : reducey Object.keyson parte de ECMA 5th edition; debe proporcionar un polyfill para los navegadores que no los admiten (especialmente IE8).

Vea una implementación predeterminada por Mozilla .


1
Útil para mantener una tienda redux cuando está utilizando un mapa de objetos y necesita soltar una de las claves
dhruvpatel

101

Si estás usando jquery:

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

44
Extraño, si doy en una variable de matriz, pone cada carácter en un objeto separado: 0: "a", 1: ",", 2: "b" ... Por lo tanto, ignora las comillas, pero incluye las comas. .
TrySpace

@Max Creo que no existe tal comportamiento. El objeto devuelto es el {0: 'a', 1: 'b', 2: 'c'}resultado esperado.
ivkremer

3
¿Hay alguna manera de usar $ .extend y al mismo tiempo informar a las teclas de manera no numérica, es decir, hacer cálculos en los elementos de la matriz?
Davi Lima

prueba súper impresionante y corta
Faisal Mehmood Awan

63

Para completar, ECMAScript 2015 (ES6) difusión. Requerirá un transpiler (Babel) o un entorno que ejecute al menos ES6.

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


2
En realidad, esto tampoco está disponible de forma nativa en ES2015. Sin embargo, es muy elegante.
Aluan Haddad

47

Probablemente lo escribiría de esta manera (ya que muy rara vez no tendré la biblioteca de subrayado a mano):

var _ = require('underscore');

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

99
¿Votaste mi respuesta pero no hiciste ningún comentario? Mi respuesta es correcta y probada. ¿Cuál es la objeción?
Dave Dopson

14
Esta pregunta no tiene una etiqueta de subrayado, y también está asumiendo node.js o una biblioteca require.
David Hellsing

10
el subrayado es bastante común tanto en el cliente como en el servidor. Se asume para Backbone.js y es probablemente LA biblioteca de utilidades más común. Dicho esto, incluí la línea require para dejar en claro que estaba usando una biblioteca. No hay una línea para describir "agregar underscore.js a su página", por lo que se requiere alguna traducción para un entorno de navegador
Dave Dopson

66
Aún así, si está utilizando un puntaje bajo, un simple obj=_.extend({},a);haría el trabajo. Además, si está iterando a través de matrices, diría _.eachque sería más apropiado que _.map. En general, esta no es una buena respuesta en varios niveles.
David Hellsing

44
Las personas "debes responder sin mencionar guiones bajos o lo-dash" son muy molestas. Comparable a decir que debe responder preguntas de C ++ sin mencionar las bibliotecas estándar. Si el guión bajo o lo-dash no es una opción, el OP debe mencionar eso.
Charlie Martin

26

Aquí hay un método O (1) ES2015 solo para completar.

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) Según MDN , cambiar el [[Prototipo]] de un objeto es una operación muy lenta. (2) Esto no elimina la lengthpropiedad propia . (3) El objeto es todavía una matriz, Array.isArray(arr) === true. (4) Los comportamientos especiales de la matriz no se eliminan, por ejemplo, arr.length = 0elimina todos los índices. (5) Por lo tanto, creo que Object.assignes mucho mejor .
Oriol

1
@Oriol mdn está equivocado, al menos en V8 (pero también en otros motores), esta es una operación bastante rápida en este caso particular, ya que los objetos tienen un almacén numérico de todos modos, esto básicamente está cambiando dos punteros.
Benjamin Gruenbaum

Esto también se puede usar por el hecho de que aparentemente es único entre las otras soluciones rápidas, de preservar cualquier propiedad no indexada ("propia") en la matriz (es decir, propiedades enteras no positivas) ...
Brett Zamir

Pero hmm, Array.isArrayestá regresando truepor el "objeto" aquí, aunque instanceof Arrayno ...
Brett Zamir

@BrettZamir que suena como un error: D
Benjamin Gruenbaum

26

Sorprendido de no ver

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


Cualquier sugerencia inteligente para crear { "first":"a", "second":"b","third":"c" }con las claves
reparadas

@mplungjan Sugeriría usar reducir en lugar de asignar en ese caso. Probablemente haya una biblioteca que le permita enumerar cada ordinal si es necesario.
Wylliam Judd

Tuve otro caso hoy. Terminé haciendo una pregunta al respecto: stackoverflow.com/questions/62197270/destruct-using-titles/…
mplungjan

23

podemos usar Object.assigny array.reducefuncionar para convertir una matriz a objeto.

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

console.log(newObj)


Esto es lo que estaba buscando. No necesitaba las indeces, necesitaba transformar la matriz en pares clave-valor retenidos.
Mike K

18

Terminé usando el operador de propagación de objetos, ya que es parte del estándar ECMAScript 2015 (ES6).

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

Hizo el siguiente violín como ejemplo.


1
No estoy seguro del rendimiento de esto, pero de tantas conversiones de Array a Objeto (ya que quiero usar objetos para todos mis códigos para estandarizarlo), esta es probablemente la más fácil.
Alguien especial

¿Cómo es esto mejor que cualquiera de las respuestas ya existentes que dieron la misma solución?
Dan Dascalescu

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

Una manera fácil en JavaScript moderno es usar Object.assign()eso que no hace más que copiar clave: valor de un objeto a otro. En nuestro caso, Arraydona propiedades a nuevos {}.


¿Cómo es esto mejor que cualquiera de las respuestas ya existentes que dieron la misma solución?
Dan Dascalescu

Dan Dascalescu en el momento en que agregué la respuesta, solo había una respuesta anterior O.assignpero carecía de explicación. Hoy en día, la desestructuración de la matriz en un objeto es una forma ( {...array})
Appeiron

14

Para ES2016, operador de propagación para objetos. Nota: Esto es después de ES6 y, por lo tanto, será necesario ajustar el transpiler.

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


La respuesta del operador de propagación ya se dio 2 años antes .
Dan Dascalescu

11

Cinco años después, hay una buena manera :)

Object.assign fue introducido en ECMAScript 2015.

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

10

Usar javascript#forEachuno puede hacer esto

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

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

Con ECMA6:

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

10

FWIW, otro enfoque reciente es utilizar el nuevo Object.fromEntriesjunto con Object.entrieslo siguiente:

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

... lo que permite evitar almacenar elementos de matriz dispersos como undefinedonull y conserva las teclas no indexadas (p. ej., números enteros no positivos / no numéricos).

arr.lengthSin embargo, es posible que desee agregar , ya que eso no está incluido:

obj.length = arr.length;


9

Si usa ES6, puede usar Object.assign y el operador de propagación

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

Si tiene una matriz anidada como

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

1
No solo los nombres de sus variables son diferentes, sino que su ejemplo no funcionará, crear un mapa desde el constructor inicialmente requiere una matriz de valor-clave 2D. new Map([['key1', 'value1'], ['key2', 'value2']]);
Shannon Hochkins

5

Una rápida y sucia:

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

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

Creo que olvidaste probar eso; Produce {0:"c", 1:"b", 2:"a"}. Usted quiere en unshiftlugar de popo (mejor) comenzar con i=arr.length-1y disminuir en su lugar.
Phrogz

sí ... simplemente lo cambié, pero luego se volvió menos interesante: /
Mic

Incluso podría hacerlo l = arr.length, y luego while (l && (obj[--l] = arr.pop())){}(me doy cuenta de que esto es viejo, pero ¿por qué no simplificarlo aún más?).
Qix - MONICA FUE MALTRATADA el

2
@Qix, buen acortamiento
Mic

4

Rápido y sucio # 2:

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

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

¿Por qué estás usando notación de coma?
Conner Ruhl

3
Preferencia personal para tener la coma en la siguiente línea. Encuentro esta notación más fácil de leer.
BingeBoy

1
El bucle se detendrá si la matriz contiene un valor falso. Debe verificar en i < a.lengthlugar de a[i].
Oriol

4

A partir de Lodash 3.0.0 puede 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

Aquí hay una función recursiva que acabo de escribir. Es simple y funciona bien.

// 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;
}

Aquí hay un ejemplo ( 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 al objeto


Funciona muy bien Gracias
Hanmaslah

Esto debería estar más arriba, si tienes ['a' = '1', 'b' = '2', 'c' = '3']y quieres que {a: 1, b: 2, c: 3}esto funcione perfectamente.
Wanjia

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

[docs]

o más detallado

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

o

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

el más corto con vainilla JS

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

algún ejemplo más complejo

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

incluso más corto (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]


¿Con qué pretendías [/docs]? Sería más útil hacer que los fragmentos de código sean ejecutables.
Dan Dascalescu

3

Yo haría esto simplemente con Array.of(). La matriz de tiene la capacidad de usar su contexto como constructor.

NOTA 2 La función of es un método de fábrica intencionalmente genérico; no requiere que este valor sea el constructor de matriz. Por lo tanto, puede ser transferido o heredado por otros constructores que pueden llamarse con un solo argumento numérico.

Entonces podemos unirnos Array.of()a una función y generar una matriz como objeto.

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

Al utilizar Array.of() uno, incluso se pueden hacer subclases de matrices .


3

Si puedes usar Mapo Object.assign, es muy fácil.

Crea una matriz:

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

Lo siguiente crea un objeto con índice como claves:

Object.assign({}, languages)

Replica lo mismo que arriba con Maps

Convierte a un objeto basado en índice, {0 : 'css'}etc.

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

Convertir a un objeto basado en valores, {css : 'css is great'}etc.

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

3

Un método simple y descarado para convertir rápidamente una matriz de elementos en un objeto

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

Luego usándolo así ...

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

Salida:

pork pie

Comprobando el tipo:

typeof obj
"object"

Y las cosas no estarían completas si no hubiera un método prototipo

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`

Salida:

cheese whizz

* TENGA EN CUENTA que no hay una rutina de nombres, por lo que si desea tener nombres específicos, deberá continuar utilizando los métodos existentes a continuación.


Método antiguo

Esto le permite generar a partir de una matriz un objeto con las claves que defina en el orden que desee.

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); generará "pintura", la función debe tener matrices de igual longitud o obtendrá un objeto vacío.

Aquí hay un método actualizado

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

Esto destruye el contenido de la matriz de claves y, a pesar del comentario interno, también la matriz de valores (su contenido). JavaScript funciona de manera diferente a PHP con JavaScript actuando automáticamente por referencia en las propiedades de un objeto / matriz.
Brett Zamir

No, no lo hace, la rutina hace copias, el original no se toca.
Mark Giblin

Sí, se toca el original. Ver jsfiddle.net/bRTv7 . Las longitudes de la matriz terminan siendo 0.
Brett Zamir

Ok, la versión editada con la que acabo de cambiarla no destruye los arreglos, me parece extraño que debería haberlo hecho.
Mark Giblin

1
Método actualizado que debería ser compatible con navegadores antiguos, ya que JSON ha existido por más tiempo que ECMA agregó nuevas características 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));

O usar

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


2

ES5 - Solución:

Usando la función de prototipo de matriz 'push' y 'apply' puede llenar el objeto con los elementos de la 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


¿Qué pasa si quiero convertirme?{ name: a, div :b, salary:c}
Prashant Pimpale

2

Más soporte para el navegador y una forma más flexible de hacerlo es usando un bucle normal , algo como:

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

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

Pero también la forma moderna podría ser usar el operador de propagación , como:

{...arr}

O asignar objeto :

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

Ambos volver :

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

1

Podrías usar una función 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 debería manejar matrices dispersas de manera más eficiente.


1

Aquí hay una solución en coffeescript

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

77
¿Qué es coffeescript? Estamos hablando de JS! : D
m93a

2
Es un pequeño lenguaje que se compila en JavaScript :)
David

66
Hmph, usa notación extraña. Me gusta más el JS simple.
m93a

2
@David Podrías hacer todo el ciclo for en 1 línea para hacer que todo sea solo 3 líneas. :) Ejemplo:obj[i] = v for v,i in arr when v?
XåpplI'-I0llwlg'I -
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.