-
-
Save lukehorvat/133e2293ba6ae96a35ba to your computer and use it in GitHub Desktop.
| let map = new Map(); | |
| map.set("a", 1); | |
| map.set("b", 2); | |
| map.set("c", 3); | |
| let obj = Array.from(map).reduce((obj, [key, value]) => ( | |
| Object.assign(obj, { [key]: value }) // Be careful! Maps can have non-String keys; object literals can't. | |
| ), {}); | |
| console.log(obj); // => { a: 1, b: 2, c: 3 } |
Instead of converting the map -> array -> iterating over array / filling in new object
Could you do this?
const convertMapsToObjects = (mapInstance) => {
const obj = {};
for(let prop of map){
obj[prop[0]] = prop[1];
}
return obj;
}
Thanks for sharing!
Major performance hit when you create a new object (with Object.assign) inside every iteration.
Because you're creating a new object literal when you call Array.reduce(fn, {}), you can safely mutate that accumulator object from within the reducer function.
This is WAYYYYY faster:
let obj = Array.from(map).reduce((obj, [key, value]) => {
obj[key] = value;
return obj;
}, {});Unfortunately, you'll never know because gist doesn't send comment notifications... I hope someone finds this comment and it helps them. Email me if it does, so I can be notified this helped someone 😉
I think with ES6 if you replace Array.from(map) with [...map.entries()], it's even faster :)
Could also be a one-liner:
let obj = [...map.entries()].reduce((obj, [key, value]) => (obj[key] = value, obj), {});
This would be the best way
const obj = map.entries().reduce((main, [key, value]) => ({...main, [key]: value,{})@IllusionElements almost has it. reduce only exists on Array, so you have to convert the map.entries() from an iterator first. And there are some brackets missing:
const obj = Array.from(map.entries()).reduce((main, [key, value]) => ({...main, [key]: value}), {})Will do the trick. @changbowen has the right answer too if you want to use the spread operator instead of Array.from().
Doing a spread operator in the loop {...main, [key]: value} is as inefficient as Object.assign() in the OP.
In contrast; obj[key] = value is simply modifying the reducer sum value, rather than recreating it on every loop.
The ES6 spread operator is indeed faster than Array.from(), but is still slower than the for of loop.
TL:DR; crude results below at 100,000 iterations of a 15 element map.
fromAssign: 1255.439ms
forOf: 109.349ms
fromReuse: 369.059ms
spreadReuse: 237.935ms
fromSpread: 4260.636ms
spreadSpread: 4094.880ms
With for...of
const obj = {};
for (let [key, value] of map) {
obj[key] = value;
}No spread & no Array.from
const newObject = theMap.keys.reduce((obj, key) => {
obj[key] = theMap.get(key);
return obj;
}, {});
You can also use forEach method
const obj = {};
map.forEach((value, key) => (obj[key] = value));@varoot provided the secret sauce.
const obj = Object.fromEntries(map.entries());
But note that Object.fromEntries is ES2019 so it's not technically "ES6" and might need additional polyfill for Node or browsers.
@varoot provided the secret sauce.
const obj = Object.fromEntries(map.entries());
const obj = {}; map.forEach((value, key) => (obj[key] = value));
no need to return anything in forEach.
map.forEach((value, key) => {obj[key] = value});
In Node 12+, just Object.fromEntries(map).
Need to think about recurisive map:
const m = new Map()
m.set('submap', new Map())export function fromMap(map) {
return Array.from
( map.entries()
, ([ k, v ]) =>
v instanceof Map
? { _mK: k, _mVal: fromMap (v) }
: { _mK: k, _mVal: v }
)
}
export function toMap(arr) {
let m = new Map()
arr.forEach(item => {
let v = item._mVal;
if (Array.isArray(v) && v[0] && v[0]._mK !== undefined) v = toMap(v)
m.set(item._mK, v)
})
return m
}
function fromMap(map) {
let obj = {}
for(let[k,v] of map) {
v instanceof Map
? obj[k] = fromMap(v)
: obj[k] = v
}
return obj
}@marcusflat: It can not reverse the object to map if so.
@marcusflat: It can not reverse the object to map if so.
function toMap(obj) {
let map = new Map()
for(let k of Object.keys(obj)) {
obj[k] instanceof Object
? map.set(k, toMap(obj[k]))
: map.set(k, obj[k]);
}
return map
}@marculsflat: your scene is that all object are the Map. but not all objects are the map in some scene.
treeMap = {
'filepath': {
name: 'filebasename',
path: 'filepath',
stat: new Stat(), // not map
children: new Map(...)
}ES6 ways
Object.fromEntries
const log = console.log;
const map = new Map();
// undefined
map.set(`a`, 1);
// Map(1) {"a" => 1}
map.set(`b`, 2);
// Map(1) {"a" => 1, "b" => 2}
map.set(`c`, 3);
// Map(2) {"a" => 1, "b" => 2, "c" => 3}
// Object.fromEntries ✅
const obj = Object.fromEntries(map);
log(`\nobj`, obj);
// obj { a: 1, b: 2, c: 3 }...spread&destructing assignment
const autoConvertMapToObject = (map) => {
const obj = {};
for (const item of [...map]) {
const [
key,
value
] = item;
obj[key] = value;
}
return obj;
}
const log = console.log;
const map = new Map();
// undefined
map.set(`a`, 1);
// Map(1) {"a" => 1}
map.set(`b`, 2);
// Map(1) {"a" => 1, "b" => 2}
map.set(`c`, 3);
// Map(2) {"a" => 1, "b" => 2, "c" => 3}
const obj = autoConvertMapToObject(map);
log(`\nobj`, obj);
// obj { a: 1, b: 2, c: 3 }Major performance hit when you create a new object (with
Object.assign) inside every iteration.Because you're creating a new object literal when you call
Array.reduce(fn, {}), you can safely mutate that accumulator object from within the reducer function.This is WAYYYYY faster:
let obj = Array.from(map).reduce((obj, [key, value]) => { obj[key] = value; return obj; }, {});Unfortunately, you'll never know because gist doesn't send comment notifications... I hope someone finds this comment and it helps them. Email me if it does, so I can be notified this helped someone 😉
this one helped me.
If a value in the map can be an array of maps you need:
const toObject = (map = new Map) => {
if (!(map instanceof Map)) return map
return Object.fromEntries(Array.from(map.entries(), ([k, v]) => {
if (v instanceof Array) {
return [k, v.map(toObject)]
} else if (v instanceof Map) {
return [k, toObject(v)]
} else {
return [k, v]
}
}))
}
You can also do this inside a custom
toJSONmethod defined for the Map instance, so that it automatically takes place whenever JavaScript'sJSON.stringifyfunction is called.