Có cách nào đơn giản để hợp nhất Bản đồ ES6 lại với nhau (như Object.assign
) không? Và trong khi chúng ta đang ở đó, còn Bộ ES6 (như thế nào Array.concat
) thì sao?
for..of
vì key
có thể là bất kỳ loại nào
Có cách nào đơn giản để hợp nhất Bản đồ ES6 lại với nhau (như Object.assign
) không? Và trong khi chúng ta đang ở đó, còn Bộ ES6 (như thế nào Array.concat
) thì sao?
for..of
vì key
có thể là bất kỳ loại nào
Câu trả lời:
Đối với bộ:
var merged = new Set([...set1, ...set2, ...set3])
Đối với bản đồ:
var merged = new Map([...map1, ...map2, ...map3])
Lưu ý rằng nếu nhiều bản đồ có cùng một khóa, giá trị của bản đồ được hợp nhất sẽ là giá trị của bản đồ hợp nhất cuối cùng với khóa đó.
Map
: Trình xây dựng của người dùng: new Map([iterable])
Trực tiếp, iterable
là một mảng hoặc đối tượng lặp khác có các phần tử là các cặp giá trị khóa (Mảng 2 phần tử). Mỗi cặp khóa-giá trị được thêm vào Bản đồ mới. - chỉ là một tài liệu tham khảo.
Map
tạo sẽ tránh tiêu thụ bộ nhớ của chúng.
Đây là giải pháp của tôi bằng cách sử dụng máy phát điện:
Đối với Bản đồ:
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' ] ]
Đối với Bộ:
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' ]
m2.forEach((k,v)=>m1.set(k,v))
nếu bạn muốn hỗ trợ trình duyệt dễ dàng
Vì những lý do tôi không hiểu, bạn không thể trực tiếp thêm nội dung của Bộ này vào bộ khác với thao tác tích hợp. Các hoạt động như union, giao nhau, hợp nhất, v.v ... là các hoạt động tập hợp khá cơ bản, nhưng không được tích hợp sẵn. May mắn thay, bạn có thể tự mình xây dựng những thứ này khá dễ dàng.
Vì vậy, để triển khai thao tác hợp nhất (hợp nhất nội dung của một Tập hợp thành một Bản đồ khác hoặc một Bản đồ khác), bạn có thể thực hiện việc này bằng một .forEach()
dòng duy nhất :
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
Và, đối với a Map
, bạn có thể làm điều này:
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);
});
Hoặc, theo cú pháp ES6:
t.forEach((value, key) => s.set(key, value));
FYI, nếu bạn muốn một lớp con đơn giản của Set
đối tượng tích hợp có chứa một .merge()
phương thức, bạn có thể sử dụng điều này:
// 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;
Điều này có nghĩa là trong tập tin setex.js của chính nó mà sau đó bạn có thể require()
vào tệp node.js và sử dụng thay cho Tập hợp tích hợp.
new Set(s, t)
. làm. Các t
tham số được bỏ qua. Ngoài ra, rõ ràng không phải là hành vi hợp lý khi add
phát hiện loại tham số của nó và nếu một tập hợp thêm các phần tử của tập hợp, bởi vì sau đó sẽ không có cách nào để thêm một tập hợp vào tập hợp.
.add()
phương pháp lấy Set, tôi hiểu quan điểm của bạn. Tôi chỉ thấy rằng việc sử dụng ít hơn nhiều so với việc có thể kết hợp các bộ bằng cách sử dụng .add()
vì tôi chưa bao giờ có nhu cầu về Bộ hoặc Bộ, nhưng tôi đã có nhu cầu hợp nhất các bộ nhiều lần. Chỉ là vấn đề quan điểm về sự hữu ích của một hành vi so với hành vi khác.
n.forEach(m.add, m)
- nó đảo ngược các cặp khóa / giá trị!
Map.prototype.forEach()
và Map.prototype.set()
có những lý lẽ đảo ngược. Có vẻ như một sự giám sát của ai đó. Nó buộc nhiều mã hơn khi cố gắng sử dụng chúng cùng nhau.
set
thứ tự tham số là tự nhiên cho các cặp khóa / giá trị,forEach
được căn chỉnh với phương thức Array
s forEach
(và những thứ như $.each
hoặc _.each
cũng liệt kê các đối tượng).
Biên tập :
Tôi đã điểm chuẩn giải pháp ban đầu của tôi so với các giải pháp khác cho thấy ở đây và thấy rằng nó rất không hiệu quả.
Bản thân điểm chuẩn rất thú vị ( liên kết ) Nó so sánh 3 giải pháp (cao hơn là tốt hơn):
- Giải pháp của @ bfred.it, bổ sung từng giá trị một (14.955 op / giây)
- Giải pháp của @ jameslk, sử dụng trình tạo tự gọi (5.089 op / giây)
- của riêng tôi, sử dụng giảm & lây lan (3,434 op / giây)
Như bạn có thể thấy, giải pháp của @ bfred.it chắc chắn là người chiến thắng.
Hiệu suất + Bất biến
Với ý nghĩ đó, đây là một phiên bản sửa đổi một chút, không làm thay đổi bộ gốc và chấp nhận một số lượng lặp có thể thay đổi để kết hợp làm đối số:
function union(...iterables) { const set = new Set(); for (let iterable of iterables) { for (let item of iterable) { set.add(item); } } return set; }
Sử dụng:
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}
Tôi muốn đề xuất một cách tiếp cận khác, sử dụng reduce
vàspread
toán tử:
function union (sets) {
return sets.reduce((combined, list) => {
return new Set([...combined, ...list]);
}, new Set());
}
Sử dụng:
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}
Tiền boa:
Chúng ta cũng có thể sử dụng rest
toán tử để làm cho giao diện đẹp hơn một chút:
function union (...sets) {
return sets.reduce((combined, list) => {
return new Set([...combined, ...list]);
}, new Set());
}
Bây giờ, thay vì truyền một mảng các tập hợp, chúng ta có thể truyền một số lượng đối số tùy ý của các tập hợp:
union(a, b, c) // {1, 2, 3, 4, 5, 6}
forof
và add
, có vẻ như rất không hiệu quả. Tôi thực sự mong muốn một addAll(iterable)
phương pháp trên Bộ
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 }
Câu trả lời được phê duyệt là tuyệt vời nhưng điều đó tạo ra một bộ mới mỗi lần.
Nếu bạn muốn đột biếnThay vào đó, một đối tượng hiện có, hãy sử dụng hàm trợ giúp.
function concatSets(set, ...iterables) {
for (const iterable of iterables) {
for (const item of iterable) {
set.add(item);
}
}
}
Sử dụng:
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);
}
}
}
Sử dụng:
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]
Để hợp nhất các bộ trong mảng Bộ, bạn có thể làm
var Sets = [set1, set2, set3];
var merged = new Set([].concat(...Sets.map(set => Array.from(set))));
Nó hơi bí ẩn đối với tôi tại sao những điều sau đây, tương đương, lại thất bại ít nhất là ở Babel:
var merged = new Set([].concat(...Sets.map(Array.from)));
Array.from
có các tham số bổ sung, thứ hai là một chức năng ánh xạ. Array.prototype.map
chuyển ba đối số cho cuộc gọi lại của nó: (value, index, array)
vì vậy, nó thực sự gọi Sets.map((set, index, array) => Array.from(set, index, array)
. Rõ ràng, index
là một số và không phải là một chức năng ánh xạ nên nó thất bại.
Sẽ không có ý nghĩa gìnew Set(...anArrayOrSet)
khi gọi khi thêm nhiều phần tử (từ một mảng hoặc một tập hợp khác) vào một tập hợp hiện có .
Tôi sử dụng điều này trong một reduce
chức năng, và nó chỉ đơn giản là ngớ ngẩn. Ngay cả khi bạn có ...array
sẵn toán tử trải, bạn không nên sử dụng nó trong trường hợp này, vì nó làm lãng phí tài nguyên bộ xử lý, bộ nhớ và thời gian.
// 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()))
Chuyển đổi các tập hợp thành các mảng, làm phẳng chúng và cuối cùng hàm tạo sẽ uniqify.
const union = (...sets) => new Set(sets.map(s => [...s]).flat());
Không, không có thao tác dựng sẵn nào cho các thao tác này, nhưng bạn có thể dễ dàng tạo chúng cho riêng mình:
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;
};
const mergedMaps = (...maps) => {
const dataMap = new Map([])
for (const map of maps) {
for (const [key, value] of map) {
dataMap.set(key, value)
}
}
return dataMap
}
const map = mergedMaps(new Map([[1, false]]), new Map([['foo', 'bar']]), new Map([['lat', 1241.173512]]))
Array.from(map.keys()) // [1, 'foo', 'lat']
Bạn có thể sử dụng cú pháp lây lan để hợp nhất chúng lại với nhau:
const map1 = {a: 1, b: 2}
const map2 = {b: 1, c: 2, a: 5}
const mergedMap = {...a, ...b}
=> {a: 5, b: 1, c: 2}
hợp nhất với bản đồ
let merge = {...map1,...map2};