javascript - Konvertera objektarray till en hashtabell, indexerad efter ett attributvärde av objektet
Användningsfall
Användningsfallet är att konvertera en array av objekt till en hashkarta baserat på en sträng eller funktion som tillhandahålls för att utvärdera och använda som nyckel i hashkartan och värde som själva objektet. Ett vanligt exempel på att använda detta är att konvertera en array av objekt till en hashkarta av objekt.
Kod
Följande är ett litet kodstycke i JavaScript för att konvertera en matris av objekt till en hashkarta, indexerad efter objektets attributvärde. Du kan tillhandahålla en funktion för att dynamiskt (i körningstid) utvärdera nyckeln för hashkartan.
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 hashmap
* @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;
};
Du kan hitta huvudpoängen här: Konverterar en array av objekt till en HashMap.
Svar #1
Detta är ganska trivialt att göra med 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' }Observera: Array.prototype.reduce() är IE9+, så om du behöver stödja äldre webbläsare måste du använda en polyfill.
Svar #2
Med ES6 Map (ganska väl stödd) kan du prova detta:
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"}Svar #3
Du kan använda den nya Object.fromEntries()-metoden.
Exempel :
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}Svar #4
Använder 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}
Svar #5
Med lodash kan detta göras med 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}
Svar #6
🏆 Tersiest
list.reduce((obj, item) => ({...obj, [item.name]: item.value}), {})
const list = [
{ name: 'abc', value: 123 },
{ name: 'xyz', value: 789 },
{ name: 'she', value: 'her' },
{ name: 'he', value: 'him'}
]
console.log(
list.reduce((obj, item) => ({...obj, [item.name]: item.value}), {})
)Svar #7
Att använda spridningsoperatorn:
const result = arr.reduce(
(accumulator, target) => ({ ...accumulator, [target.key]: target.val }),
{});
Demonstration av kodavsnittet på jsFiddle.
Svar #8
Du kan använda Array.prototype.reduce() och faktiskt JavaScript Map istället för bara ett JavaScript-objekt.
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);
Vad är skillnaden mellan Map och Object?
Tidigare, innan Map implementerades i JavaScript, har Object använts som en Map på grund av deras liknande struktur.
Beroende på ditt användningsfall, om du behöver ha ordnade nycklar, behöver komma åt storleken på kartan eller ofta lägga till och ta bort från kartan, är en Map att föredra.
Citat från MDN-dokument:
Objekt liknar Mappar eftersom båda låter dig sätta nycklar till värden, hämta dessa värden, ta bort nycklar och upptäcka om något är lagrat på en nyckel. På grund av detta (och eftersom det inte fanns några inbyggda alternativ) har objekt historiskt använts som Mappar; det finns dock viktiga skillnader som gör att det kan vara att föredra att använda en Mapp i vissa fall:
- Nycklarna i ett Object är Strängar och Symboler, medan de kan vara vilket värde som helst för en Map, inklusive funktioner, objekt och alla primitiva värden.
- Nycklarna i Map är ordnade medan nycklar som läggs till ett objekt inte är det. Således, när man itererar över det, returnerar ett Map-objekt nycklar i insättningsordning.
- Du kan enkelt få storleken på en Map med egenskapen size, medan antalet egenskaper i ett Object måste bestämmas manuellt.
- En karta är itererbar och kan därför itereras direkt, medan iteration över ett objekt kräver att man på något sätt får dess nycklar och itererar över dem.
- Ett objekt har en prototyp, så det finns standardnycklar i mappen som kan kollidera med dina nycklar om du inte är försiktig. Från och med ES5 kan detta undvikas genom att använda map=Object.create(null), men detta görs sällan.
- En karta kan prestera bättre i scenarier som involverar frekvent tillägg och borttagning av nyckelpar.
Svar #9
es2015-version:
const myMap = new Map(objArray.map(obj => [ obj.key, obj.val ]));
Svar #10
Det finns bättre sätt att göra detta som förklarats av andra inlägg. Men om jag vill hålla mig till ren JS och det gamla sättet, så här är det:
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);
