[javascript] ES6 맵 / 세트를 병합하는 가장 간단한 방법은 무엇입니까?
ES6 Maps를 같이 통합하는 간단한 방법이 Object.assign
있습니까? 그리고 우리가 그것을하고있는 동안 ES6 세트는 Array.concat
어떻습니까?
답변
세트의 경우 :
var merged = new Set([...set1, ...set2, ...set3])
지도 :
var merged = new Map([...map1, ...map2, ...map3])
여러 맵에 동일한 키가있는 경우 병합 된 맵의 값은 해당 키와 마지막으로 병합 된 맵의 값이됩니다.
답변
발전기를 사용하는 솔루션은 다음과 같습니다.
지도 :
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' ]
답변
내가 이해하지 못하는 이유로 내장 작업으로 한 세트의 내용을 다른 세트에 직접 추가 할 수 없습니다. 공용체, 교차, 병합 등과 같은 작업은 기본 설정 작업이지만 기본 제공 작업은 아닙니다. 다행스럽게도이 모든 것을 상당히 쉽게 구성 할 수 있습니다.
따라서 병합 작업을 구현하려면 (한 세트의 내용을 다른 세트로 병합하거나 하나의 맵을 다른 맵으로 병합) 한 .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);
});
또는 ES6 구문에서 :
t.forEach((value, key) => s.set(key, value));
참고로, 메소드 Set
를 포함하는 내장 오브젝트 의 간단한 서브 클래스를 원하면 .merge()
다음을 사용할 수 있습니다.
// 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;
이것은 당신이 할 수있는 자체 파일 setex.js에 있어야합니다. require()
있으며 node.js에 들어가 내장 세트 대신 사용할 .
답변
편집하다 :
다른 솔루션 제안과 비교하여 원래 솔루션을 벤치마킹했으며 매우 비효율적이라는 것을 알았습니다.
벤치 마크 자체는 매우 흥미 롭습니다 ( link ) 3 가지 솔루션을 비교합니다 (높을수록 좋습니다).
- @ bfred.it의 솔루션으로 값을 하나씩 추가합니다 (14,955 op / sec)
- 자체 호출 생성기를 사용하는 @jameslk의 솔루션 (5,089 op / sec)
- 내 자신의 감소 및 확산 (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}
원래 답변
를 사용하여 다른 접근법을 제안하고 싶습니다 reduce
.spread
연산자를 .
이행
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}
답변
승인 된 답변은 훌륭하지만 매번 새로운 세트를 만듭니다.
당신이 돌연변이 를 원한다면 대신 기존 개체를 도우미 함수를 사용합니다.
세트
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]
답변
배열 세트에서 세트를 병합하려면 다음을 수행하십시오.
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
}