ES6 Haritalarını bir araya getirmenin basit bir yolu var mı Object.assign
? Ve biz oradayken, ES6 Setlerine ne dersiniz Array.concat
?
for..of
çünkü key
herhangi bir tür olabilir
ES6 Haritalarını bir araya getirmenin basit bir yolu var mı Object.assign
? Ve biz oradayken, ES6 Setlerine ne dersiniz Array.concat
?
for..of
çünkü key
herhangi bir tür olabilir
Yanıtlar:
Setler için:
var merged = new Set([...set1, ...set2, ...set3])
Haritalar için:
var merged = new Map([...map1, ...map2, ...map3])
Birden fazla harita aynı anahtara sahipse, birleştirilmiş haritanın değerinin o anahtarla son birleştirme haritasının değeri olacağını unutmayın.
Map
“Yapıcı: new Map([iterable])
”, “ üzerindeki belgeler iterable
, öğeleri anahtar / değer çiftleri (2 öğeli Diziler) olan bir Array veya diğer yinelenebilir bir nesnedir. Her bir anahtar / değer çifti yeni Haritaya eklenir. ” - sadece referans olarak.
Map
bellek tüketimini önler.
İşte jeneratörler kullanarak benim çözüm:
Haritalar için:
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' ] ]
Setler için:
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))
kolay tarayıcı desteği istiyorsanız da güzel
Anlamadığım nedenlerden dolayı, yerleşik bir işlemle bir Setin içeriğini doğrudan diğerine ekleyemezsiniz. Birlik, kesişme, birleştirme, vb. Gibi işlemler oldukça basit küme işlemleridir, ancak yerleşik değildir. Neyse ki, bunları kolayca kendiniz inşa edebilirsiniz.
Bu nedenle, bir birleştirme işlemi uygulamak için (bir Setin içeriğini başka bir haritaya veya bir Haritaya diğerine birleştirmek), bunu tek bir .forEach()
satırla yapabilirsiniz:
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
Ve, bir için Map
, bunu yapabilirsin:
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);
});
Veya ES6 sözdiziminde:
t.forEach((value, key) => s.set(key, value));
FYI, yöntem Set
içeren yerleşik nesnenin basit bir alt sınıfını istiyorsanız .merge()
, bunu kullanabilirsiniz:
// 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;
Bu, daha require()
sonra node.js içine girebileceğiniz ve yerleşik Set yerine kullanabileceğiniz kendi setex.js dosyasında olması amaçlanmıştır .
new Set(s, t)
. İşler. t
Parametre yok sayılır. Ayrıca, add
parametresinin türünü algılamak mantıklı bir davranış değildir ve bir küme kümenin öğelerini eklerse, çünkü o zaman kümeye bir kümenin kendisini eklemenin bir yolu olmazdı.
.add()
bir Set alma yöntemine gelince , anlıyorum. Sadece .add()
bir Set veya Set'e hiç ihtiyaç duymadığım için setleri birleştirmekten çok daha az kullanıyorum , ancak setleri birçok kez birleştirmeye ihtiyacım vardı. Sadece bir davranışın diğerine karşı yararlılığı hakkında bir görüş meselesi.
n.forEach(m.add, m)
- anahtar / değer çiftlerini tersine çeviriyor!
Map.prototype.forEach()
ve Map.prototype.set()
tartışmaları tersine çevirdi. Birinin gözetimi gibi görünüyor. Bunları birlikte kullanmaya çalışırken daha fazla kod zorlar.
set
parametre sırası anahtar / değer çiftleri için doğaldır, s yöntemiyle (ve nesneler gibi veya numaralandırılan şeyler) forEach
hizalanır . Array
forEach
$.each
_.each
Düzenle :
Orijinal çözümümü burada önerdiğim diğer çözümlerle karşılaştırdım ve çok verimsiz olduğunu gördüm.
Karşılaştırmanın kendisi çok ilginç ( bağlantı ) 3 çözümü karşılaştırıyor (daha yüksek daha iyidir):
- @ bfred.it'in tek tek değer katan çözümü (14.955 op / sn)
- @ jameslk'ın kendi kendini çağıran bir jeneratör kullanan çözümü (5.089 op / sn)
- azalt ve yaymayı kullanan kendim (3.434 op / sn)
Gördüğünüz gibi @ bfred.it'in çözümü kesinlikle kazanır.
Performans + Değişmezlik
Bunu göz önünde bulundurarak, orijinal seti mutasyona uğratmayan ve argüman olarak birleştirmek için değişken sayıda yinelenebilir hariç tutan biraz değiştirilmiş bir sürüm:
function union(...iterables) { const set = new Set(); for (let iterable of iterables) { for (let item of iterable) { set.add(item); } } return set; }
Kullanımı:
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}
Kullanmak reduce
ve spread
operatör başka bir yaklaşım önermek istiyorum :
function union (sets) {
return sets.reduce((combined, list) => {
return new Set([...combined, ...list]);
}, new Set());
}
Kullanımı:
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}
İpucu:
rest
Arayüzü biraz daha hoş hale getirmek için operatörü de kullanabiliriz :
function union (...sets) {
return sets.reduce((combined, list) => {
return new Set([...combined, ...list]);
}, new Set());
}
Şimdi, bir dizi diziyi geçmek yerine, rastgele sayıda argüman geçirebiliriz :
union(a, b, c) // {1, 2, 3, 4, 5, 6}
forof
ve add
bu sadece çok verimsiz görünüyor. Gerçekten addAll(iterable)
Setler üzerinde bir yöntem diliyorum
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 }
Onaylanan cevap harika ama her seferinde yeni bir set oluşturuyor.
Bunun yerine varolan bir nesneyi değiştirmek istiyorsanız yardımcı işlevi kullanın.
function concatSets(set, ...iterables) {
for (const iterable of iterables) {
for (const item of iterable) {
set.add(item);
}
}
}
Kullanımı:
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);
}
}
}
Kullanımı:
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]
Kümeler dizisindeki kümeleri birleştirmek için şunları yapabilirsiniz:
var Sets = [set1, set2, set3];
var merged = new Set([].concat(...Sets.map(set => Array.from(set))));
Eşdeğer olması gereken aşağıdakilerin en azından Babil'de neden başarısız olduğu benim için biraz gizemli:
var merged = new Set([].concat(...Sets.map(Array.from)));
Array.from
ek parametreler alır, ikincisi bir eşleme işlevidir. Array.prototype.map
geri (value, index, array)
çağrısına üç argüman iletir: etkin bir şekilde çağırır Sets.map((set, index, array) => Array.from(set, index, array)
. Açıkçası, index
bir sayıdır ve bir eşleme işlevi değildir, bu yüzden başarısız olur.
Bu herhangi bir anlam ifade etmez çağırmak için new Set(...anArrayOrSet)
(bir dizi veya başka bir set birinden) birden çok öğe eklerken varolan kümesine .
Bunu bir reduce
işlevde kullanıyorum ve sadece aptalca. ...array
Yayılma operatörünüz olsa bile , bu durumda işlemciyi, belleği ve zaman kaynaklarını harcadığı için kullanmamalısınız.
// 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()))
Kümeleri dizilere dönüştürün, düzleştirin ve son olarak yapıcı tek kelimeyle değişecektir.
const union = (...sets) => new Set(sets.map(s => [...s]).flat());
Hayır, bunlar için yerleşik işlemler yoktur, ancak bunları kolayca kendiniz oluşturabilirsiniz:
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']
Bunları birleştirmek için forma sözdizimini kullanabilirsiniz:
const map1 = {a: 1, b: 2}
const map2 = {b: 1, c: 2, a: 5}
const mergedMap = {...a, ...b}
=> {a: 5, b: 1, c: 2}
Harita ile birleştir
let merge = {...map1,...map2};