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에 내장 된 Set 대신 사용할 수 있습니다 .
편집 :
다른 솔루션 제안과 비교하여 원래 솔루션을 벤치마킹했으며 매우 비효율적이라는 것을 알았습니다.
벤치 마크 자체는 매우 흥미 롭습니다 ( 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]
To merge the sets in the array Sets, you can do
var Sets = [set1, set2, set3];
var merged = new Set([].concat(...Sets.map(set => Array.from(set))));
It is slightly mysterious to me why the following, which should be equivalent, fails at least in Babel:
var merged = new Set([].concat(...Sets.map(Array.from)));
Based off of Asaf Katz's answer, here's a typescript version:
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
}
No, there are no builtin operations for these, but you can easily create them your own:
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']
It does not make any sense to call new Set(...anArrayOrSet)
when adding multiple elements (from either an array or another set) to an existing set.
I use this in a reduce
function, and it is just plain silly. Even if you have the ...array
spread operator available, you should not use it in this case, as it wastes processor, memory, and time resources.
// 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()))
참고URL : https://stackoverflow.com/questions/32000865/simplest-way-to-merge-es6-maps-sets
'Programing' 카테고리의 다른 글
문자열에서 처음 3자를 제거 (0) | 2020.07.03 |
---|---|
System.Web.Mvc가 참조 추가에없는 이유는 무엇입니까? (0) | 2020.07.03 |
왜 std :: move std :: shared_ptr을 사용합니까? (0) | 2020.07.03 |
TreeMap을 반복하는 방법? (0) | 2020.07.02 |
파이썬에서 객체 속성을 반복 (0) | 2020.07.02 |