क्या ES6 मैप्स को एक साथ मर्ज करने का एक सरल तरीका है (जैसे Object.assign
)? और जब हम इस पर हैं, तो ES6 सेट्स (जैसे Array.concat
) के बारे में क्या ?
for..of
क्योंकि key
किसी भी प्रकार
क्या ES6 मैप्स को एक साथ मर्ज करने का एक सरल तरीका है (जैसे Object.assign
)? और जब हम इस पर हैं, तो ES6 सेट्स (जैसे Array.concat
) के बारे में क्या ?
for..of
क्योंकि key
किसी भी प्रकार
जवाबों:
सेट के लिए:
var merged = new Set([...set1, ...set2, ...set3])
नक्शे के लिए:
var merged = new Map([...map1, ...map2, ...map3])
ध्यान दें कि यदि कई मानचित्रों में एक ही कुंजी है, तो विलय किए गए नक्शे का मूल्य उस कुंजी के साथ अंतिम विलय के नक्शे का मूल्य होगा।
Map
: "कंस्ट्रक्टर: new Map([iterable])
", " iterable
एक एरे या अन्य चलने योग्य वस्तु है जिसके तत्व कुंजी-मूल्य जोड़े (2-तत्व एरे) हैं। प्रत्येक कुंजी-मूल्य जोड़ी को नए मानचित्र में जोड़ा जाता है। " - सिर्फ एक संदर्भ के रूप में।
Map
कंस्ट्रक्टर को पुनरावृति पास करने से उनकी मेमोरी खपत से बचा जाता है।
यहाँ जनरेटर का उपयोग कर मेरा समाधान है:
मानचित्रों के लिए:
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' ]
m2.forEach((k,v)=>m1.set(k,v))
अगर आप चाहते हैं आसान ब्राउज़र समर्थन
जिन कारणों से मुझे समझ में नहीं आता है, आप एक निर्मित ऑपरेशन के साथ एक सेट की सामग्री को सीधे दूसरे में नहीं जोड़ सकते। यूनियन, इंटरसेक्ट, मर्ज, आदि जैसे ऑपरेशन ... बहुत बुनियादी सेट ऑपरेशन हैं, लेकिन बिल्ट-इन नहीं हैं। सौभाग्य से, आप इन सभी का निर्माण आसानी से कर सकते हैं।
तो, एक मर्ज ऑपरेशन को लागू करने के लिए (एक सेट की सामग्री को दूसरे या एक मैप में दूसरे में विलय करना), आप इसे एक ही .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));
FYI करें, यदि आप बिल्ट-इन 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()
बिल्ट-इन सेट के स्थान पर नोड.जेएस और उपयोग कर सकें।
new Set(s, t)
। काम करता है। t
पैरामीटर नजरअंदाज कर दिया है। इसके अलावा, यह स्पष्ट रूप से उचित व्यवहार नहीं है add
कि इसके पैरामीटर के प्रकार का पता लगाया जाए और यदि कोई सेट सेट के तत्वों को जोड़ देता है, क्योंकि तब सेट में खुद को जोड़ने का कोई तरीका नहीं होगा।
.add()
एक सेट लेने की विधि के लिए , मैं आपकी बात समझता हूं। मुझे लगता है कि सेट के संयोजन का उपयोग करने में सक्षम होने की तुलना में मैं अभी तक कम उपयोग .add()
करता हूं क्योंकि मुझे कभी सेट या सेट की आवश्यकता नहीं थी, लेकिन मुझे कई बार सेट को मर्ज करने की आवश्यकता है। बस एक व्यवहार बनाम दूसरे की उपयोगिता की राय।
n.forEach(m.add, m)
- यह कुंजी / मूल्य जोड़े को उल्टा करता है!
Map.prototype.forEach()
और Map.prototype.set()
उलटे तर्क दिए हैं। किसी के द्वारा एक निरीक्षण की तरह लगता है। यह एक साथ उपयोग करने की कोशिश करते समय अधिक कोड को मजबूर करता है।
set
कुंजी / मान युग्मों के लिए पैरामीटर ऑर्डर प्राकृतिक है, एस विधि (और वस्तुओं की तरह या जो चीजों को गणना करता है) के forEach
साथ गठबंधन किया गया है । Array
forEach
$.each
_.each
संपादित करें :
मैंने अन्य समाधानों के खिलाफ अपने मूल समाधान को यहां सुझाया और पाया कि यह बहुत अक्षम है।
बेंचमार्क अपने आप में बहुत दिलचस्प है ( लिंक ) यह 3 समाधानों की तुलना करता है (उच्चतर बेहतर है):
- @ bfred.it का समाधान, जो एक-एक करके मूल्य जोड़ता है (14,955 सेशन / सेकंड)
- @ jameslk का समाधान, जो एक स्व-आह्वान जनरेटर (5,089 सेशन / सेकंड) का उपयोग करता है
- मेरा अपना, जो कम करता है और फैलता है (3,434 सेशन / सेकंड)
जैसा कि आप देख सकते हैं, @ 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}
forof
और add
, जो अभी बहुत अक्षम है। मैं वास्तव में addAll(iterable)
सेट्स पर एक विधि की कामना करता
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 }
स्वीकृत उत्तर बहुत अच्छा है लेकिन यह हर बार एक नया सेट बनाता है।
यदि आप इसके बजाय किसी मौजूदा ऑब्जेक्ट को म्यूट करना चाहते हैं , तो एक सहायक फ़ंक्शन का उपयोग करें।
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)));
Array.from
अतिरिक्त पैरामीटर लेता है, दूसरा एक मैपिंग फ़ंक्शन है। Array.prototype.map
इसके कॉलबैक में तीन तर्क दिए गए हैं: (value, index, array)
इसलिए यह प्रभावी रूप से कॉलिंग है Sets.map((set, index, array) => Array.from(set, index, array)
। जाहिर है, index
एक संख्या है और एक मैपिंग फ़ंक्शन नहीं है इसलिए यह विफल हो जाता है।
यह किसी भी मतलब नहीं है कॉल करने के लिए new Set(...anArrayOrSet)
जब कई तत्वों को जोड़ने (या तो किसी सरणी या एक और सेट से) एक मौजूदा सेट करने के लिए ।
मैं एक reduce
फ़ंक्शन में इसका उपयोग करता हूं , और यह सिर्फ सादा मूर्खतापूर्ण है। यहां तक कि अगर आपके पास ...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))
}
}
// 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()))
सेट को सरणियों में बदलना, उन्हें समतल करना और अंत में निर्माणकर्ता uniqify करेगा।
const union = (...sets) => new Set(sets.map(s => [...s]).flat());
नहीं, इनके लिए कोई बिल्ट ऑपरेशन नहीं हैं, लेकिन आप इन्हें आसानी से अपना बना सकते हैं:
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']
आप उन्हें एक साथ मिलाने के लिए फैल सिंटैक्स का उपयोग कर सकते हैं:
const map1 = {a: 1, b: 2}
const map2 = {b: 1, c: 2, a: 5}
const mergedMap = {...a, ...b}
=> {a: 5, b: 1, c: 2}
मानचित्र में विलय करें
let merge = {...map1,...map2};