Last active
May 25, 2023 07:01
-
-
Save jung-kim/83676b2310c7c2a9c3d8 to your computer and use it in GitHub Desktop.
es6 map vs array vs obj performance test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
let looper = (callback) => { | |
let n = 2000000; | |
while (n > 0) { | |
callback(n); | |
n--; | |
} | |
} | |
let timer = (log, callback) => { | |
let start = Date.now(); | |
callback() | |
console.log(log, Date.now() - start); | |
} | |
let map = new Map(); | |
let obj = {}; | |
let ray = []; | |
timer('Map int key set took: ', () => looper(index => map.set(Math.random() * 2000000, index))); | |
timer('Obj int key set took: ', () => looper(index => obj[Math.random() * 2000000] = index)); | |
timer('ray int key set took: ', () => looper(index => ray[Math.random() * 2000000] = index)); | |
console.log(); | |
timer('Map int key get took: ', () => looper(index => {let dummylet = map.get(Math.random() * 2000000) })); | |
timer('Obj int key get took: ', () => looper(index => {let dummylet = obj[Math.random() * 2000000] })); | |
timer('ray int key get took: ', () => looper(index => {let dummylet = ray[Math.random() * 2000000] })); | |
console.log('\n\n'); | |
map = new Map(); | |
obj = {}; | |
ray = []; | |
timer('Map string key set took: ', () => looper(index => map.set('' + Math.random() * 2000000, '' + index))); | |
timer('Obj string key set took: ', () => looper(index => obj['' + Math.random() * 2000000] = '' + index)); | |
timer('ray string key set took: ', () => looper(index => ray['' + Math.random() * 2000000] = '' + index)); | |
console.log(); | |
timer('Map string key get took: ', () => looper(index => {let dummylet = map.get('' + Math.random() * 2000000) })); | |
timer('Obj string key get took: ', () => looper(index => {let dummylet = obj['' + Math.random() * 2000000] })); | |
timer('ray string key get took: ', () => looper(index => {let dummylet = ray['' + Math.random() * 2000000] })); | |
// // Example output in node v8 | |
// | |
// Map int key set took: 1072 | |
// Obj int key set took: 2460 | |
// ray int key set took: 3457 | |
// | |
// Map int key get took: 824 | |
// Obj int key get took: 1609 | |
// ray int key get took: 2246 | |
// | |
// | |
// | |
// Map string key set took: 1580 | |
// Obj string key set took: 2933 | |
// ray string key set took: 2149 | |
// | |
// Map string key get took: 1511 | |
// Obj string key get took: 1575 | |
// ray string key get took: 1818 | |
Update from May/2020 with NodeJS v12.16.2:
Map int key set took: 1419
Obj int key set took: 2249
ray int key set took: 2139
Map int key get took: 31
Obj int key get took: 2002
ray int key get took: 1825
Map string key set took: 1442
Obj string key set took: 2168
ray string key set took: 3007
Map string key get took: 32
Obj string key get took: 2167
ray string key get took: 1598
if key is index
"use strict";
let looper = (callback) =>
{
let n = 2000000;
while (n > 0) {
callback(n);
n--;
}
}
let timer = (log, callback) =>
{
console.time(log)
callback()
console.timeEnd(log)
}
let map = new Map();
let obj = {};
let ray = [];
function RandomIndex(count)
{
return Math.floor(Math.random() * count);
}
timer('Map int key set took: ', () => looper(index => map.set(RandomIndex(500), index)));
timer('Obj int key set took: ', () => looper(index => obj[RandomIndex(500)] = index));
timer('ray int key set took: ', () => looper(index => ray[RandomIndex(500)] = index));
console.log();
timer('Map int key get took: ', () => looper(index => { let dummylet = map.get(RandomIndex(500)) }));
timer('Obj int key get took: ', () => looper(index => { let dummylet = obj[RandomIndex(500)] }));
timer('ray int key get took: ', () => looper(index => { let dummylet = ray[RandomIndex(500)] }));
console.log('\n\n');
map = new Map();
obj = {};
ray = [];
timer('Map string key set took: ', () => looper(index => map.set('' + RandomIndex(500), '' + index)));
timer('Obj string key set took: ', () => looper(index => obj['' + RandomIndex(500)] = '' + index));
timer('ray string key set took: ', () => looper(index => ray['' + RandomIndex(500)] = '' + index));
console.log();
timer('Map string key get took: ', () => looper(index => { let dummylet = map.get('' + RandomIndex(500)) }));
timer('Obj string key get took: ', () => looper(index => { let dummylet = obj['' + RandomIndex(500)] }));
timer('ray string key get took: ', () => looper(index => { let dummylet = ray['' + RandomIndex(500)] }));
very handy; thanks much!. I have not seen anything except tests against pre-sorted data elsewhere (and usually integers) which is useless for real life testing. Bit of a mystery why int key set dramatically decreased in performance in Mar 2020, but overall this seems to indicate significant optimization of get (which is what I'm looking for) in every single case. That alone makes it worth while.
The fact that array is slower than Map makes little sense to me.
Here's a updated benchmark:
"use strict";
let looper = (callback) => {
let n = 2000000;
while (n > 0) {
callback(n);
n--;
}
};
let timer = (log, callback) => {
let start = Date.now();
callback();
console.log(log, Date.now() - start);
};
let map = new Map();
let obj = {};
let ray = [];
for (let i = 0; i < 2000000; i++) {
ray.push(i);
}
function RandomIndex(count) {
return Math.floor(Math.random() * count);
}
timer("Map int key set took: ", () =>
looper((index) => map.set(RandomIndex(2000000), index))
);
timer("Obj int key set took: ", () =>
looper((index) => (obj[RandomIndex(2000000)] = index))
);
timer("ray int key set took: ", () =>
looper((index) => (ray[RandomIndex(2000000)] = index))
);
console.log();
timer("Map int key get took: ", () =>
looper((index) => {
let dummylet = map.get(RandomIndex(2000000));
})
);
timer("Obj int key get took: ", () =>
looper((index) => {
let dummylet = obj[RandomIndex(2000000)];
})
);
timer("ray int key get took: ", () =>
looper((index) => {
let dummylet = ray[RandomIndex(2000000)];
})
);
console.log("\n\n");
map = new Map();
obj = {};
ray = [];
timer("Map string key set took: ", () =>
looper((index) => map.set("" + RandomIndex(2000000), "" + index))
);
timer("Obj string key set took: ", () =>
looper((index) => (obj["" + RandomIndex(2000000)] = "" + index))
);
timer("ray string key set took: ", () =>
looper((index) => (ray["" + RandomIndex(2000000)] = "" + index))
);
console.log();
timer("Map string key get took: ", () =>
looper((index) => {
let dummylet = map.get("" + RandomIndex(2000000));
})
);
timer("Obj string key get took: ", () =>
looper((index) => {
let dummylet = obj["" + RandomIndex(2000000)];
})
);
timer("ray string key get took: ", () =>
looper((index) => {
let dummylet = ray["" + RandomIndex(2000000)];
})
);
Two key points:
- As @FishOrBear pointed out, in the first test, the index needs to be integer, array is designed to be "an array", which doesn't support float keys.
- do not leave holes in array, when initializing, push the data as they go, where in the original benchmark, the array can have arbitrary gaps, which stops v8 from optimizing.
updated results
Map int key set took: 449
Obj int key set took: 432
ray int key set took: 45
Map int key get took: 31
Obj int key get took: 32
ray int key get took: 33
Map string key set took: 1176
Obj string key set took: 756
ray string key set took: 1234
Map string key get took: 33
Obj string key get took: 439
ray string key get took: 393
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I came here looking to see if Map was efficient, it made the most sense for writing my code but I wanted to know about runtimes. If I looked at your results for more complex objects or strings, I might not choose Map. Now, a couple of years later, in Chrome 79, the results tell me to choose what makes the most sense for the writer. Optimization will always improve and choosing the correct structure when writing the code is the best optimization.
Map int key set took: 887
Obj int key set took: 2698
ray int key set took: 2754
Map int key get took: 33
Obj int key get took: 1379
ray int key get took: 1366
Map string key set took: 1839
Obj string key set took: 2291
ray string key set took: 2510
Map string key get took: 554
Obj string key get took: 1966
ray string key get took: 1302