English 中文(简体)
合并ES6地图/Sets的最简单途径?
原标题: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)?

最佳回答

套数:

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

地图:

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

请注意,如果多幅地图具有同样的关键,则合并地图的价值将是最后一份与该钥匙合并的地图的价值。

问题回答

出于我不理解的原因,你不能用内在的方法将一套内容直接添加到另一套。 诸如工会、教派、合并等行动是基本的行动,但不是建构。 幸运的是,你能够非常方便地建造这些设施。


<>strong> [Added in 2021] - There is now a proposal, to add new Set/Map methods for these services, but the time of implementation is not Immediate clear. 它们似乎处于光谱过程的第二阶段(草案阶段)。

[2023年]——提案现已进入光谱过程的第三阶段(日期)。


为了实施合并作业(将一组内容合并成另一组或一个地图),你可以采用单一<代码>。

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

或者,在ES6 syntax中:

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

<>strong>[2021年]

既然现在有一项关于新提案的正式提案, 一套方法,你可以将这一多填法用于拟议的<代码>.union(方法,该方法将使用ES6+版本的ECMA文本。 请注意,根据具体情况,这套新规定是另外两套。 它没有将一组内容合并为另一组内容,而是采用了proposal中规定的那类检查。

if (!Set.prototype.union) {
    Set.prototype.union = function(iterable) {
        if (typeof this !== "object") {
            throw new TypeError("Must be of object type");
        }
        const Species = this.constructor[Symbol.species];
        const newSet = new Species(this);
        if (typeof newSet.add !== "function") {
            throw new TypeError("add method on new set species is not callable");
        }
        for (item of iterable) {
            newSet.add(item);
        }
        return newSet;
    }
}

或者,此处更完整的版本是,将欧洲海洋研究学会成文过程模型,使物种构造更加完整,并适应于旧版的 Java印,这些版本甚至可能没有<条码>。 定:

if (!Set.prototype.union) {
    Set.prototype.union = function(iterable) {
        if (typeof this !== "object") {
            throw new TypeError("Must be of object type");
        }
        const Species = getSpeciesConstructor(this, Set);
        const newSet = new Species(this);
        if (typeof newSet.add !== "function") {
            throw new TypeError("add method on new set species is not callable");
        }
        for (item of iterable) {
            newSet.add(item);
        }
        return newSet;
    }
}

function isConstructor(C) {
    return typeof C === "function" && typeof C.prototype === "object";
}

function getSpeciesConstructor(obj, defaultConstructor) {
    const C = obj.constructor;
    if (!C) return defaultConstructor;
    if (typeof C !== "function") {
        throw new TypeError("constructor is not a function");
    }

    // use try/catch here to handle backward compatibility when Symbol does not exist
    let S;
    try {
        S = C[Symbol.species];
        if (!S) {
            // no S, so use C
            S = C;
        }
    } catch (e) {
        // No Symbol so use C
        S = C;
    }
    if (!isConstructor(S)) {
        throw new TypeError("constructor function is not a constructor");
    }
    return S;
}

FYI, 如果你想要一个包含<代码>的现成代码/code>物体的简单子流,请使用:

// 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;

这本来就属于自己的档案。 j 届时,你可以<代码>require(>)输入代号,并取代《原则和规则》。

这里,我使用发动机的解决办法:

地图:

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  ]

http://www.ohchr.org。

我根据其他解决办法衡量了我的原始解决办法,并发现其效率很低。

基准本身非常有趣(https://jsperf.com/union-sets”rel=“noreferer”>link)。 比较3个解决办法(越好):

  • @fregante (formerly called @bfred.it) solution, which adds values one by one (14,955 op/sec)
  • @jameslk s solution, which uses a self invoking generator (5,089 op/sec)
  • my own, which uses reduce & spread (3,434 op/sec)

你们可以看到,“@fregante”的解决办法肯定是赢家。

Performance + Immutability

With that in mind, here s a slightly modified version which doesn t mutates the original set and excepts a variable number of iterables to combine as arguments:

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

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

  return set;
}

<><>Usage:

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}

Original Answer

我愿建议采用<条码>代谢<>和<条码>操作者:

Implementation

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

<><>Usage:

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}

<><>Tip:

我们还可以利用<代码>rest的操作者,使接口成为比方的nic:

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

现在,我们不是通过一套文件.array,而是通过一系列文件中的任意编号arguments:

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

为了将这套材料合起来,你可以这样做。

var Sets = [set1, set2, set3];

var merged = new Set([].concat(...Sets.map(set => Array.from(set))));

令我感到惊讶的是,至少巴贝勒有下列情况:

var merged = new Set([].concat(...Sets.map(Array.from)));

根据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
}

在增加多个要素(从一个阵列或另一个阵列)时,请上new Set(......an ArrayOrSet)

我在一份<条码>中使用了这一功能,这只是暗中。 即便有<代码>......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))
  }
}

Demo Snippet

// 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()))

我创建了一种帮助方法,将地图合并起来,以任何合宜的方式处理重复钥匙的价值:

const mergeMaps = (map1, map2, combineValuesOfDuplicateKeys) => {
  const mapCopy1 = new Map(map1);
  const mapCopy2 = new Map(map2);

  mapCopy1.forEach((value, key) => {
    if (!mapCopy2.has(key)) {
      mapCopy2.set(key, value);
    } else {
      const newValue = combineValuesOfDuplicateKeys
        ? combineValuesOfDuplicateKeys(value, mapCopy2.get(key))
        : mapCopy2.get(key);
      mapCopy2.set(key, newValue);
      mapCopy1.delete(key);
    }
  });

  return new Map([...mapCopy1, ...mapCopy2]);
};

const mergeMaps = (map1, map2, combineValuesOfDuplicateKeys) => {
  const mapCopy1 = new Map(map1);
  const mapCopy2 = new Map(map2);

  mapCopy1.forEach((value, key) => {
    if (!mapCopy2.has(key)) {
      mapCopy2.set(key, value);
    } else {
      const newValue = combineValuesOfDuplicateKeys
        ? combineValuesOfDuplicateKeys(value, mapCopy2.get(key))
        : mapCopy2.get(key);
      mapCopy2.set(key, newValue);
      mapCopy1.delete(key);
    }
  });

  return new Map([...mapCopy1, ...mapCopy2]);
};

const map1 = new Map([
  ["key1", 1],
  ["key2", 2]
]);

const map2 = new Map([
  ["key2", 3],
  ["key4", 4]
]);

const show = (object) => {
  return JSON.stringify(Array.from(object), null, 2)
}

document.getElementById("app").innerHTML = `
<h1>Maps are awesome!</h1>
<div>map1 = ${show(map1)}</div>
<div>map2 = ${show(map2)}</div><br>
<div>Set value of last duplicate key:<br>merged map = ${show(mergeMaps(map1, map2))}</div><br>
<div>Set value of pair-wise summated duplicate keys:<br>merged map = ${show(mergeMaps(map1, map2, (value1, value2) => value1 + value2))}</div><br>
<div>Set value of pair-wise difference of duplicate keys:<br>merged map = ${show(mergeMaps(map1, map2, (value1, value2) => value1 - value2))}</div><br>
<div>Set value of pair-wise multiplication of duplicate keys:<br>merged map = ${show(mergeMaps(map1, map2, (value1, value2) => value1 * value2))}</div><br>
<div>Set value of pair-wise quotient of duplicate keys:<br>merged map = ${show(mergeMaps(map1, map2, (value1, value2) => value1 / value2))}</div><br>
<div>Set value of pair-wise power of duplicate keys:<br>merged map = ${show(mergeMaps(map1, map2, (value1, value2) => Math.pow(value1, value2)))}</div><br>
`;
<!DOCTYPE html>
<html>

<head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
</head>

<body>
    <div id="app"></div>

    <script src="src/index.js">
    </script>
</body>

</html>

无。

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

Example

const mergedMaps = (...maps) => {
    const dataMap = new Map([])

    for (const map of maps) {
        for (const [key, value] of map) {
            dataMap.set(key, value)
        }
    }

    return dataMap
}

Usage

const map = mergedMaps(new Map([[1, false]]), new Map([[ foo ,  bar ]]), new Map([[ lat , 1241.173512]]))
Array.from(map.keys()) // [1,  foo ,  lat ]

将这套设备改装成阵列,使之平坦,最后,建筑商将统一。

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

I ve创建了一个小刀子,将使用ES6功能的任何一批电梯合并起来。 你们可以把“Set”改为“Map”,使其与地图合作。

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}

A good solution no matter if you have two or more maps to merge is to group them as an Array and use the following:

Array.prototype.merge = function () {
  return this.reduce((p, c) => Object.assign(c, p), {});
};




相关问题
selected text in iframe

How to get a selected text inside a iframe. I my page i m having a iframe which is editable true. So how can i get the selected text in that iframe.

How to fire event handlers on the link using javascript

I would like to click a link in my page using javascript. I would like to Fire event handlers on the link without navigating. How can this be done? This has to work both in firefox and Internet ...

How to Add script codes before the </body> tag ASP.NET

Heres the problem, In Masterpage, the google analytics code were pasted before the end of body tag. In ASPX page, I need to generate a script (google addItem tracker) using codebehind ClientScript ...

Clipboard access using Javascript - sans Flash?

Is there a reliable way to access the client machine s clipboard using Javascript? I continue to run into permissions issues when attempting to do this. How does Google Docs do this? Do they use ...

javascript debugging question

I have a large javascript which I didn t write but I need to use it and I m slowely going trough it trying to figure out what does it do and how, I m using alert to print out what it does but now I ...

Parsing date like twitter

I ve made a little forum and I want parse the date on newest posts like twitter, you know "posted 40 minutes ago ","posted 1 hour ago"... What s the best way ? Thanx.