Преобразование массива объектов в хэш-карту, индексированное значением атрибута объекта
Случай использования
Вариант использования - преобразование массива объектов в хэш-карту на основе строки или функции, предоставленной для оценки и использования в качестве ключа в хэш-карте и значения в качестве самого объекта. Распространенным случаем использования этого является преобразование массива объектов в хэш-карту объектов.
Код
Ниже приведен небольшой фрагмент в javascript для преобразования массива объектов в хэш-карту, проиндексированный по значению атрибута объекта. Вы можете предоставить функцию для динамической оценки ключа хэш-карты (время выполнения). Надеюсь, что это поможет любому в будущем.
function isFunction(func){
return Object.prototype.toString.call(func) === '[object Function]';
}
/**
* This function converts an array to hash map
* @param {String | function} key describes the key to be evaluated in each object to use as key for hasmap
* @returns Object
* @Example
* [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap("id")
* Returns :- Object {123: Object, 345: Object}
*
* [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap(function(obj){return obj.id+1})
* Returns :- Object {124: Object, 346: Object}
*/
Array.prototype.toHashMap = function(key){
var _hashMap = {}, getKey = isFunction(key)?key: function(_obj){return _obj[key];};
this.forEach(function (obj){
_hashMap[getKey(obj)] = obj;
});
return _hashMap;
};
Вы можете найти суть здесь: https://gist.github.com/naveen-ithappu/c7cd5026f6002131c1fa
Ответы
Ответ 1
Это довольно тривиально с Array.prototype.reduce
:
var arr = [
{ key: 'foo', val: 'bar' },
{ key: 'hello', val: 'world' }
];
var result = arr.reduce(function(map, obj) {
map[obj.key] = obj.val;
return map;
}, {});
console.log(result);
// { foo: 'bar', hello: 'world' }
Примечание. Array.prototype.reduce()
- это IE9 +, поэтому, если вам нужно поддерживать старые браузеры, вам понадобится polyfill.
Ответ 2
Используя ES6 Map (довольно хорошо поддерживается), вы можете попробовать следующее:
var arr = [
{ key: 'foo', val: 'bar' },
{ key: 'hello', val: 'world' }
];
var result = new Map(arr.map(i => [i.key, i.val]));
// When using TypeScript, need to specify type:
// var result = arr.map((i): [string, string] => [i.key, i.val])
// Unfortunately maps don't stringify well. This is the contents in array form.
console.log("Result is: " + JSON.stringify([...result]));
// Map {"foo" => "bar", "hello" => "world"}
Ответ 3
С lodash это можно сделать, используя keyBy:
var arr = [
{ key: 'foo', val: 'bar' },
{ key: 'hello', val: 'world' }
];
var result = _.keyBy(arr, o => o.key);
console.log(result);
// Object {foo: Object, hello: Object}
Ответ 4
Использование оператора спреда:
const result = arr.reduce(
(accumulator, target) => ({ ...accumulator, [target.key]: target.val }),
{});
Демонстрация фрагмента кода на jsFiddle.
Ответ 5
Использование ES6 spread + Object.assign:
array = [{key: 'a', value: 'b', redundant: 'aaa'}, {key: 'x', value: 'y', redundant: 'zzz'}]
const hash = Object.assign({}, ...array.map(s => ({[s.key]: s.value})));
console.log(hash) // {a: b, x: y}
Ответ 6
Вы можете использовать Array.prototype.reduce() и реальную карту JavaScript вместо просто объекта JavaScript.
let keyValueObjArray = [
{ key: 'key1', val: 'val1' },
{ key: 'key2', val: 'val2' },
{ key: 'key3', val: 'val3' }
];
let keyValueMap = keyValueObjArray.reduce((mapAccumulator, obj) => {
// either one of the following syntax works
// mapAccumulator[obj.key] = obj.val;
mapAccumulator.set(obj.key, obj.val);
return mapAccumulator;
}, new Map());
console.log(keyValueMap);
console.log(keyValueMap.size);
Что отличается между картой и объектом?
Ранее, до того как Map была реализована в JavaScript, Object использовался в качестве Map из-за их схожей структуры.
В зависимости от вашего варианта использования, если вам нужны заказанные ключи, вам нужен доступ к размеру карты или частое добавление и удаление с карты, карта предпочтительна.
Цитата из документа MDN:
Объекты похожи на Карты в том, что оба позволяют устанавливать ключи к значениям, извлекать эти значения, удалять ключи и определять, сохранено ли что-то в ключе. Из-за этого (и потому что не было никаких встроенных альтернатив), Объекты исторически использовались как Карты; однако есть важные отличия, которые делают использование карты предпочтительным в определенных случаях:
- Ключами объекта являются строки и символы, в то время как они могут иметь любое значение для карты, включая функции, объекты и любые примитивы.
- Ключи в Map упорядочены, а ключи, добавленные к объекту - нет. Таким образом, при итерации по нему объект Map возвращает ключи в порядке вставки.
- Вы можете легко получить размер карты с помощью свойства размера, в то время как количество свойств в объекте должно быть определено вручную.
- Карта является итеративной и, таким образом, может быть непосредственно повторена, тогда как для итерации по объекту требуется получить его ключи некоторым способом и выполнить итерации по ним.
- У объекта есть прототип, поэтому на карте есть ключи по умолчанию, которые могут столкнуться с вашими ключами, если вы не будете осторожны. Начиная с ES5 это можно обойти, используя map = Object.create(null), но это редко делается.
- Карта может работать лучше в сценариях, включающих частое добавление и удаление пар ключей.
Ответ 7
Версия es2015:
const myMap = new Map(objArray.map(obj => [ obj.key, obj.val ]));
Ответ 8
Это то, что я делаю в TypeScript. У меня есть небольшая библиотека утилит, в которую я помещаю подобные вещи.
export const arrayToHash = (array: any[], id: string = 'id') =>
array.reduce((obj, item) => (obj[item[id]] = item , obj), {})
использование:
const hash = arrayToHash([{id:1,data:'data'},{id:2,data:'data'}])
или если у вас есть идентификатор, отличный от "id"
const hash = arrayToHash([{key:1,data:'data'},{key:2,data:'data'}], 'key')
Ответ 9
Использование простого Javascript
var createMapFromList = function(objectList, property) {
var objMap = {};
objectList.forEach(function(obj) {
objMap[obj[property]] = obj;
});
return objMap;
};
// objectList - the array ; property - property as the key
Ответ 10
Вы можете использовать новый метод Object.fromEntries()
const array = [
{key: 'a', value: 'b', redundant: 'aaa'},
{key: 'x', value: 'y', redundant: 'zzz'}
]
const hash = Object.fromEntries(
array.map(e => [e.key, e.value])
)
console.log(hash) // {a: b, x: y}
Ответ 11
Есть лучшие способы сделать это, как объяснено другими авторами. Но если я хочу придерживаться чистого JS и по-старому, то вот оно:
var arr = [
{ key: 'foo', val: 'bar' },
{ key: 'hello', val: 'world' },
{ key: 'hello', val: 'universe' }
];
var map = {};
for (var i = 0; i < arr.length; i++) {
var key = arr[i].key;
var value = arr[i].val;
if (key in map) {
map[key].push(value);
} else {
map[key] = [value];
}
}
console.log(map);
Ответ 12
Небольшое улучшение по reduce
использования:
var arr = [
{ key: 'foo', val: 'bar' },
{ key: 'hello', val: 'world' }
];
var result = arr.reduce((map, obj) => ({
...map,
[obj.key] = obj.val
}), {});
console.log(result);
// { foo: 'bar', hello: 'world' }
Ответ 13
Если вы хотите перейти на новую карту ES6, сделайте следующее:
var kvArray = [['key1', 'value1'], ['key2', 'value2']];
var myMap = new Map(kvArray);
Почему вы должны использовать этот тип карты? Ну, это зависит от вас. Посмотрите на это.
Ответ 14
пытаться
let toHashMap = (a,f) => a.reduce((a,c)=> (a[f(c)]=c,a),{});
let arr=[
{id:123, name:'naveen'},
{id:345, name:"kumar"}
];
let fkey = o => o.id; // function changing object to string (key)
let toHashMap = (a,f) => a.reduce((a,c)=> (a[f(c)]=c,a),{});
console.log( toHashMap(arr,fkey) );
// Adding to prototype is NOT recommented:
//
// Array.prototype.toHashMap = function(f) { return toHashMap(this,f) };
// console.log( arr.toHashMap(fkey) );
Ответ 15
Ниже приведен небольшой фрагмент, который я создал в javascript для преобразования массива объектов в хэш-карту, индексированных по значению атрибута объекта. Вы можете предоставить функцию для оценки ключа хэш-карты динамически (время выполнения).
function isFunction(func){
return Object.prototype.toString.call(func) === '[object Function]';
}
/**
* This function converts an array to hash map
* @param {String | function} key describes the key to be evaluated in each object to use as key for hasmap
* @returns Object
* @Example
* [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap("id")
Returns :- Object {123: Object, 345: Object}
[{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap(function(obj){return obj.id+1})
Returns :- Object {124: Object, 346: Object}
*/
Array.prototype.toHashMap = function(key){
var _hashMap = {}, getKey = isFunction(key)?key: function(_obj){return _obj[key];};
this.forEach(function (obj){
_hashMap[getKey(obj)] = obj;
});
return _hashMap;
};
Здесь вы можете найти суть: https://gist.github.com/naveen-ithappu/c7cd5026f6002131c1fa
Ответ 16
С lodash
:
const items = [
{ key: 'foo', value: 'bar' },
{ key: 'hello', value: 'world' }
];
const map = _.fromPairs(items.map(item => [item.key, item.value]));
console.log(map); // { foo: 'bar', hello: 'world' }