6

I have an array of objects, where each object has a unique member called id. How do I create a Map where the id if the Map's key?

Ross
  • 14,266
  • 12
  • 60
  • 91
Baz
  • 12,713
  • 38
  • 145
  • 268
  • Could you explain a bit more, do you have an example array?.. And what output you expect. – Keith Oct 24 '16 at 13:58
  • JSPrefs for the 3 answers below are here: https://jsperf.com/array-to-map-4 – Ross Oct 24 '16 at 15:06
  • Should be pretty simple. Have you tried it yourself? Please show us your code. What did not work? – Bergi Oct 24 '16 at 15:24

3 Answers3

8

You want to reduce your array into a map:

const arr = [{id:1},{id:2},{id:2}];

const map = arr.reduce((acc, item) => acc.set(item.id, item), new Map());

console.log(map.get(1));

Here is a JSPref against using map and forEach.

In Chrome v53 reduce is fastest, then forEach with map being the slowest.

Ross
  • 14,266
  • 12
  • 60
  • 91
  • Curious to know why this got a down vote. It's not making intermediate arrays which may not be faster (and will bump the garbage collector later) – Ross Oct 24 '16 at 14:21
  • @gothdo why complex? Because it uses reduce? – Ross Oct 24 '16 at 14:23
  • I'd say for someone reading the code, this is more literate of its intension. Therefore simpler. Unless you don't know what `reduce` is of course. – Ross Oct 24 '16 at 14:29
  • Harsh downvote. It may look complex on the surface, but this is simply a pure function with no side-effects and so is easier to reason about. – CodingIntrigue Oct 24 '16 at 14:33
  • @Gothdo haha... to keep it simple – Ross Oct 24 '16 at 14:36
  • 1
    @Gothdo I've changed it to `const`. (It appears you didn't get the irony) – Ross Oct 24 '16 at 14:47
  • @Gothdo I've added a JSPref for my own curiosity. For me this runs 48% faster than using `map` – Ross Oct 24 '16 at 14:57
  • with edge, foreach is the fastest, then comes reduce and map. – Nina Scholz Oct 24 '16 at 17:15
  • Nice. Tbh very little difference on chrome between forEach and reduce on Chrome. It's allocating the arrays rather than called set which is a performance hit. – Ross Oct 24 '16 at 18:56
3

You could map a new array in the needed format for the Map.

var array = [{ id: 1, value: 'one' }, { id: 2, value: 'two' }, { id: 3, value: 'three' }, { id: 4, value: 'four' }, { id: 5, value: 'five' }],
    map = new Map(array.map(a => [a.id, a]));

console.log([...map]);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Or iterate and add the new item to a certain key

var array = [{ id: 1, value: 'one' }, { id: 2, value: 'two' }, { id: 3, value: 'three' }, { id: 4, value: 'four' }, { id: 5, value: 'five' }],
    map = new Map();

array.forEach(a => map.set(a.id, a));
console.log([...map]);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • 1
    In ES6 it's better to use for..of loop instead of `forEach()` method, see [Are there reasons to use array.forEach() over for…of, when both could be used, in ES6?](http://stackoverflow.com/q/31344516/3853934). `forEach()` is also slower than a loop. – Michał Perłakowski Oct 24 '16 at 14:21
  • but i do not need an exit of the loop. just iterating. – Nina Scholz Oct 24 '16 at 14:26
  • But you don't know if someone using this code won't need to modify it to exit the loop. And still it's slower. – Michał Perłakowski Oct 24 '16 at 14:29
  • 1
    @Gothdo Can't see how `for..of` provides any benefits over `forEach` here. In fact, using `forEach` allows for abstraction into a smaller, reusable method, e.g. `const addToMap = item => map.set(item.id, item); array.forEach(addToMap);` – CodingIntrigue Oct 24 '16 at 14:29
  • 1
    @CodingIntrigue If you want to use functional programming with composable methods, you shouldn't use side effects like `set`. So that's hardly an advantage here. At least, use `reduce` instead of `forEach` like in Ross' answer. And really, for imperative iteration (which is what we need here) `for…of` loops are more idiomatic ES6. – Bergi Oct 24 '16 at 15:26
  • @Bergi Not arguing that a pure function isn't a better choice. Just given this answer there is more benefit to forEach. Being idiomatic ES6 is subjective at best. Abstraction is quantifiable, rightly or wrongly used. – CodingIntrigue Oct 24 '16 at 16:40
3

You can use Array.prototype.map() to map the array elements to [element.id, element] pairs and then pass the resulting array to the Map constructor.

const arr = [{id: 1, a: true, b: false}, {id: 2, a: false, b: true}]

const map = new Map(arr.map(element => [element.id, element]))

// Check if map looks OK
for (const [key, value] of map) {
  console.log(key, value)
}
Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177