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

jam*_*slk 135 javascript set ecmascript-6

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

Ori*_*iol 224

套装:

var merged = new Set([...set1, ...set2, ...set3])
Run Code Online (Sandbox Code Playgroud)

对于地图:

var merged = new Map([...map1, ...map2, ...map3])
Run Code Online (Sandbox Code Playgroud)

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

  • 对于大型集合,只需要警告这会迭代两个集合的内容两次,一次创建一个包含两个集合的临时数组,然后将该临时数组传递给Set构造函数,再次迭代它以创建新集合. (23认同)
  • 关于[`Map`]的文档(https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Map):"构造函数:`new Map([iterable])`","`iterable `是一个Array或其他可迭代对象,其元素是键值对(2元素数组).每个键值对都会添加到新Map中." - 仅作为参考. (4认同)
  • @devuxer,您需要在 tsconfig.json 中启用“compilerOptions.downlevelIteration”以消除编译器错误。请参阅 /sf/ask/3740890471/ (3认同)
  • @jfriend00:请参阅下面的jameslk答案以获得更好的方法 (2认同)
  • @torazaburo:正如jfriend00所说,Oriols解决方案确实创建了不必要的中间数组.将迭代器传递给`Map`构造函数可以避免它们的内存消耗. (2认同)
  • 我很沮丧 ES6 Set/Map 没有提供有效的合并方法。 (2认同)
  • @JyotmanSingh 你说得对,对不起。我没有注意到`...` :-( 这是一个很好的答案! (2认同)

jam*_*slk 44

这是我使用生成器的解决方案:

对于地图:

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' ] ]
Run Code Online (Sandbox Code Playgroud)

套装:

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' ]
Run Code Online (Sandbox Code Playgroud)

  • (IIGFE =立即调用的生成器函数表达式) (33认同)
  • @caub不错的解决方案,但请记住forEach的第一个参数是值,因此您的函数应为m2.forEach((v,k)=> m1.set(k,v)); (5认同)
  • 对于IIGFE来说! (3认同)
  • 还好`m2.forEach((k,v)=> m1.set(k,v))`如果你想要简单的浏览器支持 (2认同)

jfr*_*d00 33

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

.forEach()检测到你正在传递另一个Set对象然后只是抓住该Set中的所有项目(这是我自己的Set对象 - 在有ES6 Set规范之前)的工作原理似乎是很自然的.但是,他们选择不以这种方式实施.

相反,您可以使用Map一行来完成:

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
Run Code Online (Sandbox Code Playgroud)

并且,对于a Set,你可以这样做:

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);
});
Run Code Online (Sandbox Code Playgroud)

  • 我不认为`新Set(s,t)`.作品.`t`参数被忽略.另外,使用`add`检测其参数的类型并且如果set添加集合的元素显然是不合理的行为,因为那样就没有办法将集合本身​​添加到集合中. (3认同)

Asa*_*atz 16

编辑:

我将我的原始解决方案与其他解决方案建议进行基准测试,并发现它效率非常低.

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

  • @ bfred.it的解决方案,逐个增加值(14,955 op/sec)
  • @jameslk的解决方案,它使用自调用生成器(5,089 op/sec)
  • 我自己的,使用减少和传播(3,434运算/秒)

如您所见,@ bfred.it的解决方案绝对是赢家.

表现+不变性

考虑到这一点,这里有一个稍微修改过的版本,它不会改变原始集合,并且可以将可变数量的iterables作为参数组合:

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

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

  return set;
}
Run Code Online (Sandbox Code Playgroud)

用法:

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}
Run Code Online (Sandbox Code Playgroud)

原始答案

我想建议另一种方法,使用reducespread运营商:

履行

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

用法:

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}
Run Code Online (Sandbox Code Playgroud)

小费:

我们也可以利用rest运算符使界面更好一些:

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

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

union(a, b, c) // {1, 2, 3, 4, 5, 6}
Run Code Online (Sandbox Code Playgroud)

  • 您答案顶部附近的 jsperf 链接似乎已损坏。另外,您参考了 bfred 的解决方案,我在此处没有看到该解决方案。 (5认同)
  • @jfriend00 当我访问“bfred.it”时,我得到了“fregante”的 Twitter 帐户,所以也许这就是 fregante 的答案! (3认同)

fre*_*nte 12

批准的答案很棒,但每次创建一个新的集合.

如果要改变现有对象,请使用辅助函数.

function concatSets(set, ...iterables) {
    for (const iterable of iterables) {
        for (const item of iterable) {
            set.add(item);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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
Run Code Online (Sandbox Code Playgroud)

地图

function concatMaps(map, ...iterables) {
    for (const iterable of iterables) {
        for (const item of iterable) {
            map.set(...item);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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]
Run Code Online (Sandbox Code Playgroud)


小智 5

要将集合合并到数组集合中,可以执行

var Sets = [set1, set2, set3];

var merged = new Set([].concat(...Sets.map(set => Array.from(set))));
Run Code Online (Sandbox Code Playgroud)

对于我来说有点神秘,为什么以下这些应该等效的至少在Babel中失败了:

var merged = new Set([].concat(...Sets.map(Array.from)));
Run Code Online (Sandbox Code Playgroud)