Преобразовать массив в объект

515

Какой лучший способ конвертировать:

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

чтобы:

{
  0: 'a',
  1: 'b',
  2: 'c'
}
Дэвид Хеллсинг
источник
3
Может быть, ему нужно, чтобы какой-нибудь код, печатающий утку, не думал, что это экземпляр Array
Pointy
6
Стоит отметить, что массивы Javascript являются объектами.
Спудли
Если кто-то еще ищет решение Lodash, подумайте _.keyBy(ранее _.indexBy): lodash.com/docs#keyBy
2540625
Это немного сбивает с толку, потому что массивы уже являются объектами, но я предполагаю, что суть вопроса заключается в преобразовании экзотического объекта массива в обычный объект .
Ориоль
1
Простой способ сделать это с Lodash есть _.toPlainObject. Пример:var myObj = _.toPlainObject(myArr)
Джулиан Соро

Ответы:

474

ECMAScript 6 представляет легко заполняемый файл Object.assign:

Этот Object.assign()метод используется для копирования значений всех перечисляемых собственных свойств из одного или нескольких исходных объектов в целевой объект. Он вернет целевой объект.

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

Собственный length свойство массива не копируется, поскольку оно не перечисляемо.

Кроме того, вы можете использовать синтаксис ES6 для достижения того же результата:

{ ...['a', 'b', 'c'] }
Ориоль
источник
Просто хочу указать - если у вас уже есть массив отсортированных свойств из исходного объекта, использование оператора распространения - это то, что превратит этот массив непосредственно в новый объект:{ ...[sortedArray]}
HappyHands31
Ориол, есть ли способ установить фиксированный ключ вместо 0 и 1?
Menai Ala Eddine
488

С такой функцией:

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

Ваш массив уже более или менее просто объект, но массивы действительно имеют некоторое «интересное» и особое поведение по отношению к целочисленным свойствам. Вышесказанное даст вам простой объект.

отредактируйте также, возможно, вы захотите учесть "дыры" в массиве:

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

В современных средах исполнения JavaScript вы можете использовать .reduce()метод:

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

Этот также позволяет избежать «дыр» в массиве, потому что так оно и .reduce()работает.

Заостренный
источник
2
@ m93a это уже объект. В JavaScript на самом деле нет смысла создавать экземпляр Array ( []), если вы не собираетесь использовать числовые ключи свойств и свойство "length".
Заостренный
15
более чистый способ избежать переназначения параметровconst obj = arr.reduce((obj, cur, i) => { return { ...obj, [i]: cur }; }, {});
huygn
3
Стрелка + деструктурирующий синтаксис без явного возврата:const obj = arr.reduce((obj, cur, i) => ({ ...obj, [i]: cur }), {});
Марк Шейб
2
@eugene_sunic действительно, но этот подход не был доступен, когда я ответил на это в 2010 году :)
Pointy
2
Как указывает @miro, создавать новый объект каждый раз не нужно, и на самом деле он намного медленнее, чем манипулирование созданным исходным объектом. Выполнение теста JSPerf для массива из 1000 элементов, создание нового объекта каждый раз в 1000 раз медленнее, чем изменение существующего объекта. jsperf.com/…
romellem
281

Вы можете использовать аккумулятор ака 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"

Передайте пустой объект {}в качестве отправной точки; затем «увеличивать» этот объект постепенно. В конце итераций resultбудет{"0": "a", "1": "b", "2": "c"}

Если ваш массив представляет собой набор объектов пары ключ-значение:

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

будет производить: {a: 1, b: 2, c: 3}

Для полноты картины reduceRightпозволяет перебирать массив в обратном порядке:

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

будет производить: {c:3, b:2, a:1}

Ваш аккумулятор может быть любого типа для конкретной цели. Например, чтобы поменять ключ и значение вашего объекта в массиве, передайте []:

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

будет производить: [{1: "a"}, {2: "b"}, {3: "c"}]

В отличие от map, reduceне может использоваться в качестве 1-1 отображения. У вас есть полный контроль над элементами, которые вы хотите включить или исключить. Поэтому reduceпозволяет добиться того filter, что делает, что делает reduceочень универсальным:

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

будет производить: [{2: "b"}, {3: "c"}]

Осторожно : reduceи Object.keyявляются частью ECMA 5th edition; Вы должны предоставить polyfill для браузеров, которые их не поддерживают (особенно IE8).

Смотрите реализацию по умолчанию от Mozilla .

Roland
источник
1
Помогает в сохранении хранилища редуксов, когда вы используете карту объектов и вам нужно уронить один из ключей
dhruvpatel
101

Если вы используете jquery:

$.extend({}, ['a', 'b', 'c']);
Максимум
источник
4
Странно, если я даю переменную Array, она помещает каждый символ в отдельный объект: 0: "a", 1: ",", 2: "b" ... Поэтому он игнорирует кавычки, но включает запятые .. .
TrySpace
@ Макс Я думаю, что такого поведения нет. Возвращенный объект - это {0: 'a', 1: 'b', 2: 'c'}то, что является ожидаемым результатом.
ивкремер
3
Есть ли способ использовать $ .extend, а также информировать ключи не числовым способом, то есть делать вычисления для элементов массива?
Дави Лима
супер крутой и короткий тест
Фейсал Мехмуд Аван
63

Для полноты распространения ECMAScript 2015 (ES6). Потребуется либо транспортер (Babel), либо среда, работающая как минимум на ES6.

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

mcmhav
источник
2
На самом деле это не изначально доступно в ES2015 либо. Это очень элегантно, однако.
Алуан Хаддад
47

Вероятно, я бы написал так (поскольку очень редко у меня не будет библиотеки underscorejs):

var _ = require('underscore');

var a = [ 'a', 'b', 'c' ];
var obj = _.extend({}, a);
console.log(obj);
// prints { '0': 'a', '1': 'b', '2': 'c' }
Дейв Допсон
источник
9
Вы отрицаете мой ответ, но без комментариев? Мой ответ правильный и проверенный. Какое возражение?
Дейв Допсон
14
У этого вопроса нет тега подчеркивания, и вы также принимаете node.js или библиотеку require.
Дэвид Хеллсинг
10
подчеркивание довольно распространено как на клиенте, так и на сервере. Предполагается, что для Backbone.js и, вероятно, самая распространенная служебная библиотека. При этом я добавил строку require, чтобы было ясно, что я использую библиотеку. Для описания «добавления underscore.js на вашу страницу» нет 1
строки
6
Тем не менее, если вы используете undserscore, простой obj=_.extend({},a);сделает эту работу. Кроме того, если вы перебираете массивы, я бы сказал, _.eachчто это более уместно, чем _.map. В общем, это не очень хороший ответ на нескольких уровнях.
Дэвид Хеллсинг
4
«Вы должны ответить без упоминания подчеркивания или пренебрежения», люди так раздражают. Сравнимо с тем, что вы должны отвечать на вопросы C ++, не упоминая стандартные библиотеки. Если подчеркивание или тупая черта не вариант, ФП должен упомянуть об этом.
Чарли Мартин
26

Вот метод O (1) ES2015 только для полноты.

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) Согласно MDN , изменение [[Prototype]] объекта является очень медленной операцией. (2) Это не удаляет собственное lengthимущество. (3) Объект все еще является массивом Array.isArray(arr) === true. (4) Специальные поведения массива не удаляются, например, arr.length = 0удаляются все индексы. (5) Поэтому я думаю, что Object.assignнамного лучше .
Ориоль
1
@ Oriol mdn не так, по крайней мере, в V8 (но также и в других движках) в данном конкретном случае это довольно быстрая операция - поскольку объекты все равно имеют числовое хранилище, это в основном меняет два указателя.
Бенджамин Грюнбаум
Это также может быть использовано для того факта, что он, по-видимому, является уникальным среди других быстрых решений сохранения любых неиндексных («собственных») свойств массива (то есть свойств, не являющихся целыми положительными числами) ...
Бретт Замир
Но хм, Array.isArrayвозвращается trueза "объект" здесь, хотя instanceof Arrayне ...
Бретт Замир
@BrettZamir, который звучит как ошибка: D
Бенджамин Грюнбаум
26

Удивлен не видеть -

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

Уильям Джадд
источник
Любое умное предложение для создания { "first":"a", "second":"b","third":"c" }с исправлением ключей - я ищу деструктив
mplungjan
@mplungjan Я бы посоветовал использовать вместо него в этом случае вместо assign. Вероятно, есть библиотека, которая позволит вам перечислять каждый ординал, если это необходимо.
Уильям Джадд
У меня был другой случай сегодня. Я задал вопрос об этом: stackoverflow.com/questions/62197270/destruct-using-titles/…
mplungjan
23

мы можем использовать Object.assignи array.reduceфункцию для преобразования массива в объект.

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

console.log(newObj)

KARTHIKEYAN.A
источник
Это то, что я искал. Мне не нужны были индексы, мне нужно было преобразовать массив в сохраненные пары ключ-значение.
Майк К
18

В итоге я использовал оператор распространения объектов, поскольку он является частью стандарта ECMAScript 2015 (ES6).

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

Сделал следующую скрипку в качестве примера.

locropulenton
источник
1
Я не уверен в производительности этого, но из такого большого количества преобразований Массив в Объект (так как я хочу использовать объекты для всех моих кодов для его стандартизации), это, вероятно, самый простой.
Кто-то
Как это лучше, чем любой из уже существующих ответов, которые дали то же самое решение?
Дан Даскалеску
17
Object.assign({}, ['one', 'two']); // {0: 'one', 1: 'two'}

В современном JavaScript простой способ - использовать Object.assign()только копирование ключа: значения из одного объекта в другой. В нашем случае Arrayжертвует свойства на новый {}.

Appeiron
источник
Как это лучше, чем любой из уже существующих ответов, которые дали то же самое решение?
Дан Даскалеску
Дэн Дакалеску в то время, когда я добавил ответ, был только выше, относительно ответа, O.assignно это не объяснялось. В настоящее время деструктурирование массива в объект является способом ( {...array})
Appeiron
14

Для ES2016, оператор распространения для объектов. Примечание: это после ES6 и поэтому необходимо настроить транспортер.

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

Алексей Трехлеб
источник
Ответ оператора спреда был дан уже 2 года назад .
Дан Даскалеску
11

Пять лет спустя, есть хороший способ :)

Object.assign был представлен в ECMAScript 2015.

Object.assign({}, ['a', 'b', 'c'])
// {'0':'a', '1':'b', '2':'c'}
Пол Дрэйпер
источник
10

Используя javascript#forEachодин можно сделать это

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

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

С ECMA6:

attributes.forEach((prop,index)=>result[index] = prop);
РИЯ ХАН
источник
10

FWIW, еще один недавний подход заключается в использовании нового Object.fromEntriesнаряду со Object.entriesследующим:

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

... что позволяет избежать хранения разреженных элементов массива как undefinedилиnull и сохраняет неиндексные (например, не положительно-целые / не числовые) ключи.

arr.lengthТем не менее, можно добавить , что это не входит:

obj.length = arr.length;
Бретт Замир
источник
9

Вы можете использовать спред оператора

x = [1,2,3,10]
{...x} // {0:1, 1:2, 2:3, 3:10}
Ноэль Зубин
источник
1
Этот ответ уже был дан несколько раз.
Дан Даскалеску
9

Если вы используете ES6, вы можете использовать Object.assign и оператор распространения

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

Если у вас есть вложенный массив, как

var arr=[[1,2,3,4]]
Object.assign(...arr.map(d => ({[d[0]]: d[1]})))
Мурти Найка К
источник
1
Мало того, что ваши имена переменных различаются, но ваш пример не будет работать, для создания карты из конструктора изначально требуется 2d массив значений ключа. new Map([['key1', 'value1'], ['key2', 'value2']]);
Шеннон Хохкинс,
5

Быстрый и грязный:

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

while( l && (obj[--l] = arr.pop() ) ){};
микрофон
источник
Я думаю, что вы забыли проверить это; это производит {0:"c", 1:"b", 2:"a"}. Вы или хотите unshiftвместо popили (лучше) начать с i=arr.length-1и уменьшить вместо.
Phrogz
да .. просто изменил это, но потом стало менее интересно: /
Mic
Мог бы даже l = arr.lengthи потом while (l && (obj[--l] = arr.pop())){}(я понимаю, что это старо, но почему бы не упростить его еще дальше).
Qix - МОНИКА ПРОИЗОШЛА
2
@Qix, Хорошее сокращение
Мик
4

Быстро и грязно # 2:

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

while( a[i] ) { s[i] = a[i++] };
lordkrandel
источник
Почему вы используете запятую?
Коннер Рухл
3
Личное предпочтение ставить запятую на следующей строке. Я считаю эту запись проще для чтения.
BingeBoy
1
Цикл остановится, если массив содержит ложное значение. Вы должны проверить i < a.lengthвместо a[i].
Ориоль
4

Начиная с Lodash 3.0.0 вы можете использовать _.toPlainObject

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

acontell
источник
3

Вот рекурсивная функция, которую я только что написал. Это просто и хорошо работает.

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

Вот пример ( 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));

Результаты: Рекурсивный массив для объекта

JVE999
источник
Работает действительно хорошо. Спасибо
Hanmaslah
Это должно быть выше, если у вас есть ['a' = '1', 'b' = '2', 'c' = '3']и хотите, чтобы {a: 1, b: 2, c: 3}это работало идеально.
Ваньцзя
3
.reduce((o,v,i)=>(o[i]=v,o), {})

[DOCS]

или более многословный

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

или

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

самый короткий с ванильным JS

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

более сложный пример

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

еще короче (используя 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 ] }

[/ Документы]

test30
источник
Что вы намеревались [/docs]? Было бы более полезно сделать исполняемые фрагменты кода.
Дан Даскалеску
3

Я бы сделал это просто с Array.of(). Массив имеет возможность использовать его контекст в качестве конструктора.

ПРИМЕЧАНИЕ 2. Функция является намеренно общим заводским методом; это не требует, чтобы это значение было конструктором Array. Поэтому он может быть передан или унаследован другими конструкторами, которые могут быть вызваны с одним числовым аргументом.

Таким образом, мы можем связываться Array.of()с функцией и генерировать массив, подобный объекту.

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

Используя Array.of() его, можно даже выполнять подклассификацию массива .

Redu
источник
3

Если вы можете использовать MapилиObject.assign , это очень легко.

Создать массив:

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

Ниже создается объект с индексом в качестве ключей:

Object.assign({}, languages)

Повторите то же, что и выше, с помощью Карт.

Преобразует в индексный объект и {0 : 'css'}т. Д.

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

Преобразовать в объект, основанный на значении и {css : 'css is great'}т. Д.

const valueMap = new Map(languages.map(name => [name, `${name} is great!`] ));
valueMap.get('css') // css is great
Шеннон Хохкинс
источник
3

Простой и дерзкий метод быстрого преобразования массива предметов в объект

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

Тогда, используя это так ...

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

Вывод:

pork pie

Проверка типа:

typeof obj
"object"

И вещи не были бы завершены, если бы не было метода-прототипа

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

Используя как:

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

Вывод:

cheese whizz

* ОБРАТИТЕ ВНИМАНИЕ, что подпрограммы именования не существует, поэтому, если вы хотите иметь конкретные имена, вам нужно будет продолжать использовать существующие методы ниже.


Более старый метод

Это позволяет генерировать из массива объект с ключами, которые вы определяете в том порядке, в котором вы их хотите.

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); выведет «paint», функция должна иметь массивы равной длины, иначе вы получите пустой объект.

Вот обновленный метод

Array.prototype.toObject = function(keys){
    var obj = {};
    if( keys.length == this.length)
        while( keys.length )
            obj[ keys.pop() ] = this[ keys.length ];
    return obj;
};
Марк Гиблин
источник
Это уничтожает как содержимое массива ключей, так и, несмотря на внутренний комментарий, также массив значений (его содержимое). JavaScript работает не так, как PHP, и JavaScript автоматически действует по ссылке на свойства объекта / массива.
Бретт Замир
Нет, нет, рутина делает копии, оригинал не трогается.
Марк Гиблин
Да, оригинал тронут. См. Jsfiddle.net/bRTv7 . Длина массива в конечном итоге равна 0.
Бретт Замир
Хорошо, отредактированная версия, с которой я только что изменил ее, не уничтожает массивы, считает странным, что это должно было быть сделано.
Марк Гиблин
1
Обновленный метод, который должен поддерживаться в старых браузерах, поскольку JSON существует дольше, чем ECMA, добавил новые функции кода
Марк Гиблин,
2

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

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

console.log(arrayToObject(myArray));

Или использовать

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

Bashirpour
источник
2

ES5 - Решение:

Используя функции прототипа Array «push» и «apply», вы можете заполнить объект элементами массива.

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

SridharKritha
источник
Что делать, если я хочу преобразовать в{ name: a, div :b, salary:c}
Prashant Pimpale
2

Более поддерживаемый браузер и более гибкий способ сделать это, используя обычный цикл , что-то вроде:

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

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

Но и современным способом может быть использование оператора распространения , например:

{...arr}

Или объект назначить :

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

Оба вернутся :

{0: "a", 1: "b", 2: "c"}
Алиреза
источник
1

Вы можете использовать такую ​​функцию:

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

Этот должен обрабатывать разреженные массивы более эффективно.

Пабло Кабрера
источник
1

Вот решение в coffeescript

arrayToObj = (arr) ->
  obj = {}
  for v,i in arr
    obj[i] = v if v?
  obj
Дэвид
источник
7
Что такое coffeescript? Мы говорим о JS! : D
m93a
2
Это маленький язык, который компилируется в JavaScript :)
David
6
Хммм, он использует странные обозначения. Мне больше нравится простой JS.
m93a
2
@David Вы можете сделать весь цикл for в 1 строку, чтобы сделать все это только 3 строки. :) Пример:obj[i] = v for v,i in arr when v?
XåpplI'-I0llwlg'I -