5

I recently converted some code that made use of regular objects as maps to the new es6 Map class. I encountered an issue pretty quickly as, while the Map class includes a forEach like Array, it does not include a some method along with many other Array.prototype methods.

To give some context, the original code with regular JS objects looked something like this:

var map = {
    entry1: 'test',
    entry2: 'test2'
};

Object.keys(map).some(key => {
    var value = map[key];
    // Do something...found a match
    return true;
});

The Map class does include an entries method but sadly this returns an Iterator object. This doesn't include any easy way to access the Array.prototype methods either.

I'm curious if there's a clean way to do this or if I'm barking up the wrong tree.

KhalilRavanna
  • 4,679
  • 3
  • 22
  • 23

3 Answers3

5

Use the Map#values to get an iterator of the values, and the spread syntax or Array#from (a question of style) to convert the iterator to an array:

const map = new Map([['a', 1], ['b', 2], ['c', 3]]);

const result = [...map.values()].some((value) => value > 2);

console.log(result);

As noted in @Paulpro comment you can use the same method to iterate Map#entries, and Map#keys. For example, using Array#reduce to convert the Map to an object. As Array#from invokes Map#entries we don't need to call it explicitly:

const map = new Map([['a', 1], ['b', 2], ['c', 3]]);

const result = Array.from(map.entries()).reduce((obj, [key, value]) => {
  obj[key] = value;
  return obj;
}, {});

console.log(result);
Community
  • 1
  • 1
Ori Drori
  • 145,770
  • 24
  • 170
  • 162
  • 1
    +1, Also, if you want to use the key in the test use `map.keys()` or if you want both the key and value use `map.entries()` and use `([key,value])` for the arrow function's signature. – Paul Jan 08 '17 at 22:12
  • True, an es6 way. Except it doesn't seem like it's any better than what the OP is doing – Juan Mendes Jan 08 '17 at 22:14
  • Don't use spread syntax for type conversion, use the more explicit `Array.from`. Use spread syntax only when you need to construct an array of multiple elements. – Bergi Jan 08 '17 at 22:24
  • @Bergi - please elaborate. – Ori Drori Jan 08 '17 at 22:25
  • [It's considered better style](http://stackoverflow.com/a/40549565/1048572) – Bergi Jan 08 '17 at 22:29
  • If it's a stylish preference, with iterators I prefer spread. Although `Array#from` is better when you need the entries. Thanks for the info. – Ori Drori Jan 08 '17 at 22:34
1

Call Array.from upon the Map object and invoke some on that:

Array.from(map).some(([key, value]) => /* something */ true)

Of course that's horribly inefficient. A much better idea is to define a some function that does work on any iterator, such as the ones that Map provides:

function some(it, pred) {
    for (const v of it)
        if (pred(v))
            return true;
    return false;
}

some(map.values(), value => /* something */ true)
Bergi
  • 513,640
  • 108
  • 821
  • 1,164
0

It seems like the easiest way to solve this would be some sort of way to convert a Map's entries to an Array but I haven't found any clean way to do this. Currently my solution along those lines is to define a method like this to do the conversion:

mapEntriesAsArray (map) {
    const entries = [];
    map.forEach((entry, type) => entries.push([type, entry]));
    return entries;
}

Perhaps I could throw that on the Map.prototype but that seems pretty hacky and I'm sure I'd have to fight with TypeScript by adding a d.ts file or something to make it jive without errors.

KhalilRavanna
  • 4,679
  • 3
  • 22
  • 23