जावास्क्रिप्ट में सेट को कैसे मैप / कम / फ़िल्टर करें?


132

क्या जावास्क्रिप्ट में map/ reduce/ filter/ आदि के लिए कोई रास्ता है Setया मुझे अपना खुद का लिखना होगा?

यहाँ कुछ समझदार Set.prototypeएक्सटेंशन हैं

Set.prototype.map = function map(f) {
  var newSet = new Set();
  for (var v of this.values()) newSet.add(f(v));
  return newSet;
};

Set.prototype.reduce = function(f,initial) {
  var result = initial;
  for (var v of this) result = f(result, v);
  return result;
};

Set.prototype.filter = function filter(f) {
  var newSet = new Set();
  for (var v of this) if(f(v)) newSet.add(v);
  return newSet;
};

Set.prototype.every = function every(f) {
  for (var v of this) if (!f(v)) return false;
  return true;
};

Set.prototype.some = function some(f) {
  for (var v of this) if (f(v)) return true;
  return false;
};

चलो थोड़ा सा सेट लेते हैं

let s = new Set([1,2,3,4]);

और कुछ बेवकूफ छोटे कार्य करता है

const times10 = x => x * 10;
const add = (x,y) => x + y;
const even = x => x % 2 === 0;

और देखें कि वे कैसे काम करते हैं

s.map(times10);    //=> Set {10,20,30,40}
s.reduce(add, 0);  //=> 10
s.filter(even);    //=> Set {2,4}
s.every(even);     //=> false
s.some(even);      //=> true

क्या यह अच्छा नहीं है? हाँ, मैं भी ऐसा ही सोचता हूँ। तुलना करें कि बदसूरत पुनरावृत्ति उपयोग के लिए

// puke
let newSet = new Set();
for (let v in s) {
  newSet.add(times10(v));
}

तथा

// barf
let sum = 0;
for (let v in s) {
  sum = sum + v;
}

क्या जावास्क्रिप्ट में पूरा करने mapऔर reduceउपयोग करने का कोई बेहतर तरीका है Set?


मैप-कम-इन- Setएंग के साथ समस्या यह है कि सेट्स फ़ंक्टर नहीं हैं।
बार्टेक बानचेविच

@BartekBanachewicz हाँ, यह एक समस्या की तरह है ... सही है?
धन्यवाद

2
खैर, विचार करें var s = new Set([1,2,3,4]); s.map((a) => 42);। यह तत्वों की संख्या में परिवर्तन करता है, जो mapआमतौर पर करने वाला नहीं है। इससे भी बदतर अगर आप केवल रखी गई वस्तुओं के हिस्सों की तुलना कर रहे हैं, क्योंकि तब तकनीकी रूप से यह अनिर्दिष्ट है कि आपको कौन सा मिलेगा।
बार्टेक बानचेविकेज़

मैंने उस पर विचार किया था, लेकिन मुझे यकीन नहीं है कि मैं (व्यक्तिगत रूप से) इसे अमान्य मानूंगा। ठीक है तो कम से कम forEachउस परिदृश्य के लिए मौजूद है, लेकिन reduceतब क्यों नहीं ?
धन्यवाद

4
कुछ संबंधित पढ़ने: esdiscuss.org/topic/set-some-every-reduce-filter-map-methods
CodingIntrigue

जवाबों:


105

इसे करने के लिए एक शॉर्ट-हैंड तरीका है, इसे ES6 स्प्रेड ऑपरेटर के माध्यम से एक ऐरे में बदलना है।

फिर सभी सरणी फ़ंक्शन आपके लिए उपलब्ध हैं।

const mySet = new Set([1,2,3,4]);
[...mySet].reduce()

1
क्योंकि फ़ंक्शन सेट के लिए उपलब्ध नहीं हैं! यह एक पूर्ण, निर्देशित और समझा जाने वाला वर्कअराउंड है जो इस विषय में अभी तक मौजूद नहीं है। तथ्य यह है कि 'अधिक समय लगता है' सेट अप इन सुविधाओं को लागू करने तक वर्कअराउंड के लिए भुगतान करने के लिए एक दुखद कीमत है!
ZephDavies

1
इस और Array.from के बीच अंतर क्या है
pete

9
मेरे लिए कम से कम, इस के बीच का अंतर है और Array.fromवह Array.fromटाइपस्क्रिप्ट के साथ काम करता है। प्रयोग [...mySet]त्रुटि देता है:TS2461: Type 'Set<number>' is not an array type.
मिकाल मैडसेन

1
फैलाने के लिए Array.from (), देखें stackoverflow.com/a/40549565/5516454 मूल रूप से, दोनों ही यहाँ उपयोग करने योग्य हैं। Array.from () अतिरिक्त रूप से सरणी-जैसी ऑब्जेक्ट कर सकते हैं जो @@iteratorविधि को लागू नहीं करते हैं ।
ZephDavies

अभी भी टाइपस्क्रिप्ट के साथ मेरे लिए काम नहीं करता है। मुझे मिलता हैERROR TypeError: this.sausages.slice is not a function
साइमन_वेवर

22

टिप्पणियों से चर्चा का योग करने के लिए: जबकि सेट नहीं करने के लिए कोई तकनीकी कारण नहीं हैं reduce, यह वर्तमान में प्रदान नहीं किया गया है और हम केवल ईएस 7 में बदलाव की उम्मीद कर सकते हैं।

के रूप में map, इसे अकेले बुलाना Setअड़चन का उल्लंघन हो सकता है , इसलिए यहां इसकी उपस्थिति बहस का विषय हो सकती है।

किसी फ़ंक्शन के साथ मैपिंग पर विचार करें (a) => 42- यह सेट के आकार को 1 में बदल देगा, और यह वही हो सकता है जो आप चाहते थे।

यदि आप इसका उल्लंघन करने के साथ ठीक हैं, क्योंकि जैसे आप वैसे भी मोड़ने वाले हैं, तो आप mapउन्हें पास करने से पहले हर तत्व पर भाग को लागू कर सकते हैं reduce, इस प्रकार स्वीकार करते हैं कि मध्यवर्ती संग्रह ( जो इस बिंदु पर सेट नहीं है ) कम होने के लिए डुप्लिकेट तत्व हो सकते हैं। यह प्रसंस्करण करने के लिए ऐरे में परिवर्तित करने के लिए अनिवार्य रूप से बराबर है।


1
यह ज्यादातर अच्छा है, सिवाय इसके (ऊपर दिए गए कोड का उपयोग करते हुए), s.map(a => 42)इसके परिणामस्वरूप Set { 42 }मैप किया गया परिणाम एक अलग लंबाई होगा लेकिन इसमें "डुप्लिकेट" तत्व नहीं होंगे। शायद शब्दांकन अपडेट करें और मैं इस उत्तर को स्वीकार करूंगा।
धन्यवाद

@naomik ओह derp जब मैं लिख रहा था कि मैं अपनी पहली कॉफी खत्म कर रहा था। दूसरे लुक पर, इंटरमीडिएट संग्रह को कम करने के लिए तत्काल तत्व हो सकते हैं यदि आप स्वीकार करते हैं कि यह एक सेट नहीं है - तो मेरा मतलब है।
बार्टेक बानचेविच

ओह, मैं इसे प्राप्त करता हूं - मानचित्र को एक ही प्रकार से मैप करना पड़ता है, इसलिए गंतव्य सेट में संभव टकराव होता है। जब मुझे यह सवाल मिला तो मैं सोच रहा था कि मानचित्र एक सेट से एक सरणी के लिए मैप करेगा। (जैसे कि आपने सेट किया था ।toArray ()। map।) (
सिमोन_वेर

2
स्काला और हास्केल में, सेट एक मैप ऑपरेशन का समर्थन करते हैं - यह सेट में तत्वों की संख्या को कम कर सकता है।
वेलिज़ार हिस्त्रोव

8

map/ reduce/ filterपर Map/ Setसंग्रह की कमी का कारण मुख्य रूप से वैचारिक चिंताएं हैं। जावास्क्रिप्ट में प्रत्येक संग्रह प्रकार वास्तव में केवल इसकी अनुमति देने के लिए अपने स्वयं के पुनरावृत्त तरीकों को निर्दिष्ट करना चाहिए

const mySet = new Set([1,2,3]);
const myMap = new Map([[1,1],[2,2],[3,3]]);

mySet.map(x => x + 1);
myMap.map(([k, x]) => [k, x + 1]);

के बजाय

new Set(Array.from(mySet.values(), x => x + 1));
new Map(Array.from(myMap.entries(), ([k, x]) => [k, x + 1]));

एक विकल्प यह था कि नक्शा / घटाना / फ़िल्टर को चलने योग्य / पुनरावृत्त प्रोटोकॉल के हिस्से के रूप में निर्दिष्ट किया जाए, क्योंकि entries/ values/ keysरिटर्न Iteratorएस। यह बोधगम्य है, हालांकि हर चलने योग्य भी "नीच" नहीं है। एक अन्य विकल्प इस उद्देश्य के लिए एक अलग "संग्रह प्रोटोकॉल" निर्दिष्ट करना था।

हालाँकि, मैं ES पर इस विषय पर वर्तमान चर्चा नहीं जानता।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.