pouya
pouya

Reputation: 3776

Invert a Map object

I was wondering, what is the most convenient way to invert keys and values in a Map. Is there any builtin method or should it be done by iterating over keys and values?

const map: Map<string, number> = new Map()
const inverse: Map<number, string>

Upvotes: 23

Views: 18101

Answers (3)

trincot
trincot

Reputation: 351288

You could pass the inverse tuples to the constructor, using Array.from and Array#reverse:

new Map(Array.from(origMap, a => a.reverse() as [number,string]))

See it run on an example:

const origMap = new Map([["a", 1],["b", 2]]);
console.log(...origMap);

// Reverse:
const inv = new Map(Array.from(origMap, a => a.reverse()));
console.log(...inv);

Specific for TypeScript: even though a is of the type [string, number], TypeScript does not regard a.reverse() to be of of the type [number, string], but as the more generic (string | number)[], which is not the type of pairs we need for the Map constructor argument.

The addition of as [number, string] deals with that. In plain JavaScript you would leave that out.

Upvotes: 36

ggorlen
ggorlen

Reputation: 57344

You can use the spread operator on your original map to obtain key-value array pairs which you can .map to swap each pair. Lastly, dump the result into the Map constructor for your copy. Any duplicate keys will be lost.

const orig = new Map([["a", 1], ["b", 2]]);
const cpy = new Map([...orig].map(e => e.reverse()));

console.log([...orig]);
console.log([...cpy]);

This is terse but does involve an extra array creation as pointed out by the inimitable trincot. That's only an issue if the maps are large.

By the way, if your original values are indeed numbers and aren't sparse, consider using a plain old array for your "flipped" map. This might improve performance and semantics, entirely dependent on your use case.

Upvotes: 5

Nicholas Tower
Nicholas Tower

Reputation: 85191

Given the assumption that there are no duplicate values, you can do an inverse like this:

const map: Map<string, number> = new Map();
map.set('3', 3);
map.set('4', 4);

const inverse: Map<number, string> = new Map();
map.forEach((value, key) => inverse.set(value, key));

Upvotes: 6

Related Questions