Simplest way to merge ES6 Maps/Sets?

es6 set
javascript set union
set to array javascript
lodash merge maps
javascript map
typescript set
es6 merge objects
javascript set equality

Is there a simple way to merge ES6 Maps together (like Object.assign)? And while we're at it, what about ES6 Sets (like Array.concat)?

For sets:

var merged = new Set([...set1, ...set2, ...set3])

For maps:

var merged = new Map([...map1, ...map2, ...map3])

Note that if multiple maps have the same key, the value of the merged map will be the value of the last merging map with that key.

Simplest way to merge ES6 Maps/Sets?, Is there a simple way to merge ES6 Maps together (like Object.assign)? And while we're at it, what about ES6 Sets (like Array.concat)?  ES6 introduces two new data structures − maps and sets. Let us learn about them in detail. Maps. A map is an ordered collection of key-value pairs. Maps are similar to objects. However, there are some differences between maps and objects. These are listed below −

Here's my solution using generators:

For Maps:

let map1 = new Map(), map2 = new Map();

map1.set('a', 'foo');
map1.set('b', 'bar');
map2.set('b', 'baz');
map2.set('c', 'bazz');

let map3 = new Map(function*() { yield* map1; yield* map2; }());

console.log(Array.from(map3)); // Result: [ [ 'a', 'foo' ], [ 'b', 'baz' ], [ 'c', 'bazz' ] ]

For Sets:

let set1 = new Set(['foo', 'bar']), set2 = new Set(['bar', 'baz']);

let set3 = new Set(function*() { yield* set1; yield* set2; }());

console.log(Array.from(set3)); // Result: [ 'foo', 'bar', 'baz' ]

ECMAScript 6: maps and sets, The Map data structure in ECMAScript 6 lets you use arbitrary values as keys and is highly welcome. Basic operations #. Working with single  ES6 includes two data structures which help programmers get work done without reinventing the wheel. These two data structures are those of Sets and Maps. A Set can be thought of as a collection of elements that are both unordered, and unique. That is the key to remember. The purpose of a Set is to guarantee the uniqueness of its items.

For reasons I do not understand, you cannot directly add the contents of one Set to another with a built-in operation. Operations like union, intersect, merge, etc... are pretty basic set operations, but are not built-in. Fortunately, you can construct these all yourself fairly easily.

So, to implement a merge operation (merging the contents of one Set into another or one Map into another), you can do this with a single .forEach() line:

var s = new Set([1,2,3]);
var t = new Set([4,5,6]);

t.forEach(s.add, s);
console.log(s);   // 1,2,3,4,5,6

And, for a Map, you could do this:

var s = new Map([["key1", 1], ["key2", 2]]);
var t = new Map([["key3", 3], ["key4", 4]]);

t.forEach(function(value, key) {
    s.set(key, value);
});

Or, in ES6 syntax:

t.forEach((value, key) => s.set(key, value));

FYI, if you want a simple subclass of the built-in Set object that contains a .merge() method, you can use this:

// subclass of Set that adds new methods
// Except where otherwise noted, arguments to methods
//   can be a Set, anything derived from it or an Array
// Any method that returns a new Set returns whatever class the this object is
//   allowing SetEx to be subclassed and these methods will return that subclass
//   For this to work properly, subclasses must not change behavior of SetEx methods
//
// Note that if the contructor for SetEx is passed one or more iterables, 
// it will iterate them and add the individual elements of those iterables to the Set
// If you want a Set itself added to the Set, then use the .add() method
// which remains unchanged from the original Set object.  This way you have
// a choice about how you want to add things and can do it either way.

class SetEx extends Set {
    // create a new SetEx populated with the contents of one or more iterables
    constructor(...iterables) {
        super();
        this.merge(...iterables);
    }

    // merge the items from one or more iterables into this set
    merge(...iterables) {
        for (let iterable of iterables) {
            for (let item of iterable) {
                this.add(item);
            }
        }
        return this;        
    }

    // return new SetEx object that is union of all sets passed in with the current set
    union(...sets) {
        let newSet = new this.constructor(...sets);
        newSet.merge(this);
        return newSet;
    }

    // return a new SetEx that contains the items that are in both sets
    intersect(target) {
        let newSet = new this.constructor();
        for (let item of this) {
            if (target.has(item)) {
                newSet.add(item);
            }
        }
        return newSet;        
    }

    // return a new SetEx that contains the items that are in this set, but not in target
    // target must be a Set (or something that supports .has(item) such as a Map)
    diff(target) {
        let newSet = new this.constructor();
        for (let item of this) {
            if (!target.has(item)) {
                newSet.add(item);
            }
        }
        return newSet;        
    }

    // target can be either a Set or an Array
    // return boolean which indicates if target set contains exactly same elements as this
    // target elements are iterated and checked for this.has(item)
    sameItems(target) {
        let tsize;
        if ("size" in target) {
            tsize = target.size;
        } else if ("length" in target) {
            tsize = target.length;
        } else {
            throw new TypeError("target must be an iterable like a Set with .size or .length");
        }
        if (tsize !== this.size) {
            return false;
        }
        for (let item of target) {
            if (!this.has(item)) {
                return false;
            }
        }
        return true;
    }
}

module.exports = SetEx;

This is meant to be in it's own file setex.js that you can then require() into node.js and use in place of the built-in Set.

19. Maps and Sets, Set. 19.4.1. Basic operations; 19.4.2. Setting up a Set; 19.4.3. Comparing Set elements; 19.4.4. Iterating; 19.4.5. Why can't I configure how Maps and Sets compare keys and values? 19.6.3. To combine map1 and map2 , I turn them into Arrays via the spread operator ( . ES6 Maps don't let you do this directly. But you  Sets and maps will be (are) finally available in ES6! No more spartan way to manipulate data structures. This chapter explains how we can deal with Map, Set, WeakMap and WeakSet. WeakMaps provides…

ES6 Sets and Maps – Vegibit, Is there a simple way to merge ES6 Maps together (like Object.assign)? And while we're at it, what about ES6 Sets (like Array.concat)? For sets: var merged  Java has lists, sets, maps, queues. Ruby has hashes and arrays. JavaScript, up until now, had only arrays. Objects and arrays were the workhorses of JavaScript. ES6 introduces four new data structures that will add power and expressiveness to the language: Map, Set, WeakSet, and WeakMap.

The approved answer is great but that creates a new set every time.

If you want to mutate an existing object instead, use a helper function.

Set
function concatSets(set, ...iterables) {
    for (const iterable of iterables) {
        for (const item of iterable) {
            set.add(item);
        }
    }
}

Usage:

const setA = new Set([1, 2, 3]);
const setB = new Set([4, 5, 6]);
const setC = new Set([7, 8, 9]);
concatSets(setA, setB, setC);
// setA will have items 1, 2, 3, 4, 5, 6, 7, 8, 9
Map
function concatMaps(map, ...iterables) {
    for (const iterable of iterables) {
        for (const item of iterable) {
            map.set(...item);
        }
    }
}

Usage:

const mapA = new Map().set('S', 1).set('P', 2);
const mapB = new Map().set('Q', 3).set('R', 4);
concatMaps(mapA, mapB);
// mapA will have items ['S', 1], ['P', 2], ['Q', 3], ['R', 4]

Map, Let's expand our learning of Sets and Maps in ES6 right now. ES6 Sets. Sets are collections that deal with single values or single objects. For example, let's see how this works here. C# Classes And Objects · Setting Up A Database With Seeding · 9 New Array Functions in ES6 · Simple Styling Techniques For React  > let map = new Map(); > map.set('foo', true); > map.set('bar', false); > map.size 2 > map.clear(); > map.size 0 Setting up a map # You can set up a map via an iterable over key-value “pairs” (arrays with 2 elements). One possibility is to use an array (which is iterable):

ES6 Maps in Depth, Objects vs. Maps. Object is similar to Map —both let you set keys to values, To count how many entries are in a Map , use Map.prototype.size . get Spread operator essentially converts a Map to an Array let merged = new  How do I merge two javascript objects together in ES6+? good way to merge deeply nested objects issue but the easiest solution in ES2015/ES6 is actually quite

Merge Arrays in one with ES6 Array spread · GitHub, That'll make it so much easier for you to internalize the concepts discussed in the series. Here's how what we had earlier looks like with ES6 maps. var map = new Map() map.set ('contra', { description: 'Asynchronous flow control' }) You could also use a for..of loop, and we could combine that with  Merge Arrays in one with ES6 Array spread. GitHub Gist: instantly share code, notes, and snippets.

Read Understanding ECMAScript 6, PierBover commented on Aug 24, 2016. So how do you make that dynamic for any number of arrays? It works great with useState(), but the useEffect() is not triggered when the Set dependency is changed. Here's the . Simplest way to merge ES6 Maps/Sets? 168.

Comments
  • This blog post has some insight. 2ality.com/2015/01/es6-set-operations.html
  • AFAIK for the Map you'll need to use for..of because key can be any type
  • Documentation on Map: "Constructor: new Map([iterable])", "iterable is an Array or other iterable object whose elements are key-value pairs (2-element Arrays). Each key-value pair is added to the new Map." — just as a reference.
  • For large Sets, just be warned that this iterates the content of both Sets twice, once to create a temporary array containing the union of the two sets, then passes that temporary array to the Set constructor where it is iterated again to create the new Set.
  • @jfriend00: see jameslk's answer below for a better method
  • @torazaburo: as jfriend00 said, Oriols solution does create unnecessary intermediate arrays. Passing an iterator to the Map constructor avoids their memory consumption.
  • I'm bummed that ES6 Set/Map don't provide efficient merge methods.
  • (IIGFE = Immediately-Invoked Generator Function Expression)
  • nice also m2.forEach((k,v)=>m1.set(k,v)) if you want easy browser support
  • @caub nice solution but remeber that the first parameter of forEach is value so your function should be m2.forEach((v,k)=>m1.set(k,v));
  • I don't think new Set(s, t). works. The t parameter is ignored. Also, it is obviously not reasonable behavior to have add detect the type of its parameter and if a set add the elements of the set, because then there would be no way to add a set itself to a set.
  • @torazaburo - as for the .add() method taking a Set, I understand your point. I just find that of far less use than being able to combine sets using .add() as I've never ever had a need for a Set or Sets, but I've had a need to merge sets many times. Just a matter of opinion of usefulness of one behavior vs. the other.
  • Argh, I hate that this doesn't work for maps: n.forEach(m.add, m) - it does invert key/value pairs!
  • @Bergi - yeah, it is odd that Map.prototype.forEach() and Map.prototype.set() have reversed arguments. Seems like an oversight by someone. It forces more code when trying to use them together.