合并ES6地图/集的最简单方法是什么?

时间:2015-08-14 01:11:35

标签: javascript set ecmascript-6

是否有将ES6地图合并在一起的简单方法(如Object.assign)?虽然我们在这里,但ES6套装(如Array.concat)?

12 个答案:

答案 0 :(得分:187)

对于集合:

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

对于地图:

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

请注意,如果多个地图具有相同的键,则合并地图的值将是具有该键的最后一个合并地图的值。

答案 1 :(得分:34)

这是我使用发电机的解决方案:

对于地图:

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' ] ]

对于集合:

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' ]

答案 2 :(得分:26)

由于我不明白的原因,您不能通过内置操作直接将一个Set的内容添加到另一个Set。

.add()检测到你正在传递另一个Set对象,然后只是抓住该Set中的所有项目(这就是我的own Set object之前 - 看起来很自然ES6 Set规范)有效。但是,他们选择不以这种方式实施。

相反,您可以使用一条.forEach()行:

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

而且,对于Map,你可以这样做:

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);
});

答案 3 :(得分:15)

  

修改

     

我将原始解决方案与其他解决方案进行基准比较,并发现它效率很低。

     

基准测试本身非常有趣(link)它比较了3种解决方案(越高越好):

     
      
  • @ bfred.it&#39的解决方案,逐个增加值(14,955 op / sec)
  •   
  • @jameslk的解决方案,它使用自动调用生成器(5,089 op / sec)
  •   
  • 我自己的,使用reduce&差价(3,434 op / sec)
  •   
     

正如你所看到的,@ bfred.it的解决方案绝对是胜利者。

     

表现+不变性

     

考虑到这一点,这里有一个稍微修改过的版本,但并没有   改变原始集合,并将可变数量的迭代次数除外   结合作为参数:

function union(...iterables) {
  const set = new Set();

  for (let iterable of iterables) {
    for (let item of iterable) {
      set.add(item);
    }
  }

  return set;
}
     

<强>用法:

const a = new Set([1, 2, 3]);
const b = new Set([1, 3, 5]);
const c = new Set([4, 5, 6]);

union(a,b,c) // {1, 2, 3, 4, 5, 6}

原始答案

我想建议另一种方法,使用reducespread运算符:

实施

function union (sets) {
  return sets.reduce((combined, list) => {
    return new Set([...combined, ...list]);
  }, new Set());
}

<强>用法:

const a = new Set([1, 2, 3]);
const b = new Set([1, 3, 5]);
const c = new Set([4, 5, 6]);

union([a, b, c]) // {1, 2, 3, 4, 5, 6}

提示

我们还可以使用rest运算符来使界面更好:

function union (...sets) {
  return sets.reduce((combined, list) => {
    return new Set([...combined, ...list]);
  }, new Set());
}

现在,我们可以传递任意数量的参数集合,而不是传递数组集合:

union(a, b, c) // {1, 2, 3, 4, 5, 6}

答案 4 :(得分:12)

批准的答案很棒但每次都会创建一个新的集合。

如果您想改为 mutate 现有对象,请使用辅助函数。

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

用法:

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

地图

function concatMaps(map, ...iterables) {
    for (const iterable of iterables) {
        for (const item of iterable) {
            map.set(...item);
        }
    }
}

用法:

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]

答案 5 :(得分:1)

合并到地图

 let merge = {...map1,...map2};

答案 6 :(得分:1)

将集合转换成数组,将它们展平,最后构造函数将进行唯一化。

const union = (...sets) => new Set(sets.map(s => [...s]).flat());

答案 7 :(得分:0)

不,这些没有内置操作,但您可以轻松地创建它们自己:

Map.prototype.assign = function(...maps) {
    for (const m of maps)
        for (const kv of m)
            this.add(...kv);
    return this;
};

Set.prototype.concat = function(...sets) {
    const c = this.constructor;
    let res = new (c[Symbol.species] || c)();
    for (const set of [this, ...sets])
        for (const v of set)
            res.add(v);
    return res;
};

答案 8 :(得分:0)

基于Asaf Katz的回答,这是打字稿版本:

export function union<T> (...iterables: Array<Set<T>>): Set<T> {
  const set = new Set<T>()
  iterables.forEach(iterable => {
    iterable.forEach(item => set.add(item))
  })
  return set
}

答案 9 :(得分:0)

在将多个元素(来自数组或另一个集合)添加到现有集合中时,调用new Set(...anArrayOrSet) 没有任何意义

我在reduce函数中使用了它,这简直是愚蠢的。即使您拥有...array扩频运算符,在这种情况下也不应使用它,因为它浪费了处理器,内存和时间资源。

// Add any Map or Set to another
function addAll(target, source) {
  if (target instanceof Map) {
    Array.from(source.entries()).forEach(it => target.set(it[0], it[1]))
  } else if (target instanceof Set) {
    source.forEach(it => target.add(it))
  }
}

演示代码段

// Add any Map or Set to another
function addAll(target, source) {
  if (target instanceof Map) {
    Array.from(source.entries()).forEach(it => target.set(it[0], it[1]))
  } else if (target instanceof Set) {
    source.forEach(it => target.add(it))
  }
}

const items1 = ['a', 'b', 'c']
const items2 = ['a', 'b', 'c', 'd']
const items3 = ['d', 'e']

let set

set = new Set(items1)
addAll(set, items2)
addAll(set, items3)
console.log('adding array to set', Array.from(set))

set = new Set(items1)
addAll(set, new Set(items2))
addAll(set, new Set(items3))
console.log('adding set to set', Array.from(set))

const map1 = [
  ['a', 1],
  ['b', 2],
  ['c', 3]
]
const map2 = [
  ['a', 1],
  ['b', 2],
  ['c', 3],
  ['d', 4]
]
const map3 = [
  ['d', 4],
  ['e', 5]
]

const map = new Map(map1)
addAll(map, new Map(map2))
addAll(map, new Map(map3))
console.log('adding map to map',
  'keys', Array.from(map.keys()),
  'values', Array.from(map.values()))

答案 10 :(得分:0)

您可以使用spread syntax将它们合并在一起:

const map1 = {a: 1, b: 2}
const map2 = {b: 1, c: 2, a: 5}

const mergedMap = {...a, ...b}

=> {a: 5, b: 1, c: 2}

答案 11 :(得分:0)

我创建了一个小片段来使用 ES6 中的函数合并任意数量的 Set。您可以将“设置”更改为“地图”以使其与地图一起使用。

const mergeSets = (...args) => {
    return new Set(args.reduce((acc, current) => {
        return [...acc, ...current];
    }, []));
};

const foo = new Set([1, 2, 3]);
const bar = new Set([1, 3, 4, 5]);

mergeSets(foo, bar); // Set(5) {1, 2, 3, 4, 5}
mergeSets(foo, bar, new Set([6])); // Set(6) {1, 2, 3, 4, 5, 6}