समानता के लिए ECMA6 सेट की तुलना करना


102

आप दो जावास्क्रिप्ट सेट की तुलना कैसे करते हैं? मैं उपयोग करने की कोशिश ==और ===लेकिन दोनों वापसी झूठी।

a = new Set([1,2,3]);
b = new Set([1,3,2]);
a == b; //=> false
a === b; //=> false

ये दो सेट समान हैं, क्योंकि परिभाषा के अनुसार, सेट में ऑर्डर नहीं है (कम से कम आमतौर पर नहीं)। मैंने MDN पर सेट के लिए प्रलेखन को देखा है और कुछ भी उपयोगी नहीं पाया है। क्या कोई जानता है कि इसे कैसे करना है?


दो सेट दो अलग-अलग ऑब्जेक्ट हैं। ===मूल्य समानता के लिए है, वस्तु समानता नहीं है।
एलक्लेनर्स

3
प्रत्येक सदस्य के मान को पुनरावृत्त करें और तुलना करें, यदि सभी समान हों, तो सेट "समान" है
dandavis

1
@dandavis सेट के साथ, सदस्यों हैं मान।

2
सेट और मैप्स में एक ऑर्डर होता है, जो प्रविष्टि क्रम है - जो भी कारण से: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
CodeManX

8
सबसे बुरा, यहां तक ​​कि new Set([1,2,3]) != new Set([1,2,3])। इससे जावास्क्रिप्ट सेट के सेट के लिए बेकार हो जाता है क्योंकि सुपरसेट में डुप्लिकेट सबसेट होंगे। एकमात्र वर्कअराउंड जो मन को स्प्रिंग्स करता है, सभी सबसेट को सरणियों में परिवर्तित कर रहा है, प्रत्येक एरे को सॉर्ट कर रहा है और फिर प्रत्येक एरो को स्ट्रिंग के रूप में एन्कोडिंग करता है (उदाहरण के लिए JSON)।
7vujy0f0hy

जवाबों:


73

इसे इस्तेमाल करे:

var a = new Set([1,2,3]);
var b = new Set([1,3,2]);

alert(eqSet(a, b)); // true

function eqSet(as, bs) {
    if (as.size !== bs.size) return false;
    for (var a of as) if (!bs.has(a)) return false;
    return true;
}

एक अधिक कार्यात्मक दृष्टिकोण होगा:

var a = new Set([1,2,3]);
var b = new Set([1,3,2]);

alert(eqSet(a, b)); // true

function eqSet(as, bs) {
    return as.size === bs.size && all(isIn(bs), as);
}

function all(pred, as) {
    for (var a of as) if (!pred(a)) return false;
    return true;
}

function isIn(as) {
    return function (a) {
        return as.has(a);
    };
}

allसमारोह सभी iterable वस्तुओं (जैसे के लिए काम करता है Setऔर Map)।

यदि Array.fromअधिक व्यापक रूप से समर्थित होता तो हम इस प्रकार allकार्य को कार्यान्वित कर सकते थे :

function all(pred, as) {
    return Array.from(as).every(pred);
}

उम्मीद है की वो मदद करदे।


2
मुझे लगता है कि आप का नाम बदलना चाहिए hasकरने के लिए isPartOfया isInयाelem
Bergi

@Bergi मैंने फ़ंक्शन hasका नाम बदल दिया है isIn
18:08 बजे आदित एम शाह जूल

1
@DavidGiven हाँ, जावास्क्रिप्ट में सेट सम्मिलन क्रम में पुनरावृत्त हैं: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Aadit M Shah

48
हर दिन मैं जावास्क्रिप्ट के बारे में अधिक आश्वस्त हूं जो अब तक की सबसे घटिया भाषा है। हर किसी को अपनी सीमा का सामना करने के लिए अपने स्वयं के बुनियादी कार्यों का आविष्कार करना पड़ता है, और यह ईएस 6 में है, और हम 2017 में हैं! वे सेट ऑब्जेक्ट के विनिर्देश में ऐसे लगातार कार्य क्यों नहीं जोड़ सकते हैं!
गजानन G ’

2
@ घासन-सकफ, मैं सहमत हूं, यह शायद यह है कि TC39 में वैज्ञानिक शामिल हैं, लेकिन कोई व्यावहारिक नहीं है ...
मिरकी

59

आप भी आजमा सकते हैं:

var a = new Set([1,2,3]);
var b = new Set([1,3,2]);

isSetsEqual = (a, b) => a.size === b.size && [...a].every(value => b.has(value));

console.log(isSetsEqual(a,b)) 


निश्चित रूप से एक बेहतर समाधान के रूप में यह एक अगर हालत के अंदर फिट बैठता है
ह्यूगोडी

मैं प्यार करता हूँ कि यह समाधान कितना मुहावरेदार है, और कितना पठनीय है! धन्यवाद @ मोम
दिवास्वप्न

29

लॉश प्रदान करता है _.isEqual(), जो गहरी तुलना करता है। यह बहुत आसान है अगर आप अपना खुद का लिखना नहीं चाहते हैं। 4 दर्ज के रूप में, _.isEqual()ठीक से सेट की तुलना करता है।

const _ = require("lodash");

let s1 = new Set([1,2,3]);
let s2 = new Set([1,2,3]);
let s3 = new Set([2,3,4]);

console.log(_.isEqual(s1, s2)); // true
console.log(_.isEqual(s1, s3)); // false

7

अन्य उत्तर ठीक काम करेगा; यहाँ एक और विकल्प है।

// Create function to check if an element is in a specified set.
function isIn(s)          { return elt => s.has(elt); }

// Check if one set contains another (all members of s2 are in s1).
function contains(s1, s2) { return [...s2] . every(isIn(s1)); }

// Set equality: a contains b, and b contains a
function eqSet(a, b)      { return contains(a, b) && contains(b, a); }

// Alternative, check size first
function eqSet(a, b)      { return a.size === b.size && contains(a, b); }

हालांकि, ध्यान रखें कि ऐसा नहीं है गहरी समानता की तुलना । इसलिए

eqSet(Set([{ a: 1 }], Set([{ a: 1 }])

झूठा लौटेगा। यदि उपरोक्त दो सेटों को समान माना जाता है, तो हमें प्रत्येक तत्व पर गहरी गुणवत्ता की तुलना करने वाले दोनों सेटों के माध्यम से पुनरावृति करने की आवश्यकता है। हम एक deepEqualदिनचर्या के अस्तित्व को निर्धारित करते हैं । फिर तर्क होगा

// Find a member in "s" deeply equal to some value
function findDeepEqual(s, v) { return [...s] . find(m => deepEqual(v, m)); }

// See if sets s1 and s1 are deeply equal. DESTROYS s2.
function eqSetDeep(s1, s2) {
  return [...s1] . every(a1 => {
    var m1 = findDeepEqual(s2, a1);
    if (m1) { s2.delete(m1); return true; }
  }) && !s2.size;
}

यह क्या करता है: s1 के प्रत्येक सदस्य के लिए, s2 के एक समान बराबर सदस्य के लिए देखें। यदि पाया जाता है, तो इसे हटा दें ताकि इसे फिर से उपयोग न किया जा सके। यदि s1 में सभी तत्व s2 में पाए जाते हैं, तो दो सेट गहरे समान हैं, और s2 समाप्त हो जाता है । Untested।

आपको यह उपयोगी लग सकता है: http://www.2ality.com/2015/01/es6-set-operations.html


6

इन समाधानों में से कोई भी डेटा संरचना जैसे सेट के सेट पर अपेक्षित कार्यक्षमता "वापस" नहीं लाता है अपनी वर्तमान स्थिति में, जावास्क्रिप्ट सेट इस उद्देश्य के लिए बेकार है क्योंकि सुपरसेट में डुप्लिकेट सबसेट होंगे, जिसे जावास्क्रिप्ट गलत तरीके से अलग देखता है। एकमात्र उपाय जिसके बारे में मैं सोच सकता हूं, वह प्रत्येक उपसेट को Array में परिवर्तित कर रहा है , इसे सॉर्ट कर रहा है और फिर स्ट्रिंग के रूप में एन्कोडिंग (उदाहरण के लिए JSON)।

उपाय

var toJsonSet = aset /* array or set */ => JSON.stringify([...new Set(aset)].sort()); 
var fromJsonSet = jset => new Set(JSON.parse(jset));

मूल उपयोग

var toJsonSet = aset /* array or set */ => JSON.stringify([...new Set(aset)].sort()); 
var fromJsonSet = jset => new Set(JSON.parse(jset));

var [s1,s2] = [new Set([1,2,3]), new Set([3,2,1])];
var [js1,js2] = [toJsonSet([1,2,3]), toJsonSet([3,2,1])]; // even better

var r = document.querySelectorAll("td:nth-child(2)");
r[0].innerHTML = (toJsonSet(s1) === toJsonSet(s2)); // true
r[1].innerHTML = (toJsonSet(s1) == toJsonSet(s2)); // true, too
r[2].innerHTML = (js1 === js2); // true
r[3].innerHTML = (js1 == js2); // true, too

// Make it normal Set:
console.log(fromJsonSet(js1), fromJsonSet(js2)); // type is Set
<style>td:nth-child(2) {color: red;}</style>

<table>
<tr><td>toJsonSet(s1) === toJsonSet(s2)</td><td>...</td></tr>
<tr><td>toJsonSet(s1) == toJsonSet(s2)</td><td>...</td></tr>
<tr><td>js1 === js2</td><td>...</td></tr>
<tr><td>js1 == js2</td><td>...</td></tr>
</table>

अंतिम परीक्षण: सेट का सेट

var toSet = arr => new Set(arr);
var toJsonSet = aset /* array or set */ => JSON.stringify([...new Set(aset)].sort()); 
var toJsonSet_WRONG = set => JSON.stringify([...set]); // no sorting!

var output = document.getElementsByTagName("code"); 
var superarray = [[1,2,3],[1,2,3],[3,2,1],[3,6,2],[4,5,6]];
var superset;

Experiment1:
    superset = toSet(superarray.map(toSet));
    output[0].innerHTML = superset.size; // incorrect: 5 unique subsets
Experiment2:
    superset = toSet([...superset].map(toJsonSet_WRONG));
    output[1].innerHTML = superset.size; // incorrect: 4 unique subsets
Experiment3:
    superset = toSet([...superset].map(toJsonSet));
    output[2].innerHTML = superset.size; // 3 unique subsets
Experiment4:
    superset = toSet(superarray.map(toJsonSet));
    output[3].innerHTML = superset.size; // 3 unique subsets
code {border: 1px solid #88f; background-color: #ddf; padding: 0 0.5em;}
<h3>Experiment 1</h3><p>Superset contains 3 unique subsets but Javascript sees <code>...</code>.<br>Let’s fix this... I’ll encode each subset as a string.</p>
<h3>Experiment 2</h3><p>Now Javascript sees <code>...</code> unique subsets.<br>Better! But still not perfect.<br>That’s because we didn’t sort each subset.<br>Let’s sort it out...</p>
<h3>Experiment 3</h3><p>Now Javascript sees <code>...</code> unique subsets. At long last!<br>Let’s try everything again from the beginning.</p>
<h3>Experiment 4</h3><p>Superset contains 3 unique subsets and Javascript sees <code>...</code>.<br><b>Bravo!</b></p>


1
महान समाधान! और अगर आप जानते हैं कि आपको बस स्ट्रिंग्स या संख्याओं का एक सेट मिला है, तो यह बस बन जाता है[...set1].sort().toString() === [...set2].sort().toString()

3

आपके दृष्टिकोण के झूठे होने का कारण यह है कि आप दो अलग-अलग वस्तुओं की तुलना कर रहे हैं (भले ही उन्हें एक ही सामग्री मिली हो), इस प्रकार दो अलग-अलग वस्तुओं (संदर्भ नहीं, बल्कि वस्तुओं) की तुलना हमेशा आपको झूठी लगती है।

निम्नलिखित दृष्टिकोण दो सेटों को एक में मिला देता है और बस मूर्खतापूर्ण रूप से आकार की तुलना करता है। यदि यह समान है, तो यह समान है:

const a1 = [1,2,3];
const a2 = [1,3,2];
const set1 = new Set(a1);
const set2 = new Set(a2);

const compareSet = new Set([...a1, ...a2]);
const isSetEqual = compareSet.size === set2.size && compareSet.size === set1.size;
console.log(isSetEqual);

अपसाइड : यह बहुत सरल और छोटा है। कोई बाहरी पुस्तकालय केवल वैनिला जेएस

नकारात्मक पक्ष : यह शायद मूल्यों पर चलने की तुलना में धीमी गति से होने वाला है और आपको अधिक स्थान की आवश्यकता है।


1

==, === के साथ दो वस्तुओं की तुलना करना

का उपयोग करते समय ==या ===ऑपरेटर दो वस्तुओं की तुलना करने के लिए, आप हमेशा मिल जाएगा false , जब तक कि उन ऑब्जेक्ट संदर्भ एक ही वस्तु । उदाहरण के लिए:

var a = b = new Set([1,2,3]); // NOTE: b will become a global variable
a == b; // <-- true: a and b share the same object reference

अन्यथा, == झूठ के बराबर है, भले ही वस्तु में समान मूल्य हों:

var a = new Set([1,2,3]);
var b = new Set([1,2,3]);
a == b; // <-- false: a and b are not referencing the same object

आपको मैनुअल तुलना पर विचार करने की आवश्यकता हो सकती है

ECMAScript 6 में, आप सेट को पहले से सरणियों में बदल सकते हैं ताकि आप उन दोनों के बीच अंतर कर सकें:

function setsEqual(a,b){
    if (a.size !== b.size)
        return false;
    let aa = Array.from(a); 
    let bb = Array.from(b);
    return aa.filter(function(i){return bb.indexOf(i)<0}).length==0;
}

नोट: Array.from मानक ECMAScript 6 सुविधाओं में से एक है, लेकिन यह आधुनिक ब्राउज़रों में व्यापक रूप से समर्थित नहीं है। संगतता तालिका यहां देखें: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#Browser_compatibility


1
क्या यह उस सदस्य की पहचान करने में विफल होगा, bजिसके सदस्य नहीं हैं a?

1
@torazaburo वास्तव में। यह जाँचने का सबसे अच्छा तरीका है कि सदस्य bनहीं हैं या नहीं, aयह जाँचना है a.size === b.size
आदित एम शाह

1
रखो a.size === b.sizeशॉर्ट सर्किट के लिए सबसे पहले अलग-अलग तत्वों की तुलना यदि आवश्यक हो तो नहीं?

2
यदि आकार भिन्न है, तो परिभाषा के अनुसार सेट बराबर नहीं हैं, इसलिए पहले उस स्थिति की जांच करना बेहतर है।

1
खैर, यहां दूसरा मुद्दा यह है कि सेटों की प्रकृति के अनुसार, hasसेट indexOfपर संचालन को सरणियों के विपरीत, बहुत कुशल बनाया गया है । इसलिए, अपने फ़िल्टर फंक्शन को बदलने के लिए यह समझ में आता है return !b.has(i)। यह bएक सरणी में बदलने की आवश्यकता को भी समाप्त कर देगा ।


1

स्वीकार किए गए उत्तर के आधार पर Array.from, यहां एक-लाइनर का समर्थन है:

function eqSet(a, b) {
    return a.size === b.size && Array.from(a).every(b.has.bind(b));
}

या एरो फ़ंक्शंस और प्रसार ऑपरेटर संभालने वाला एक सच्चा वन-लाइनर: eqSet = (a,b) => a.size === b.size && [...a].every(b.has.bind(b))
जॉन हॉफ़र

1

यदि सेट में केवल आदिम डेटा प्रकार होते हैं या सेट के अंदर ऑब्जेक्ट में संदर्भ समानता होती है, तो सरल तरीका है

const isEqualSets = (set1, set2) => (set1.size === set2.size) && (set1.size === new Set([...set1, ...set2]).size);


0

मैं परीक्षणों में इस दृष्टिकोण का पालन करता हूं:

let setA = new Set(arrayA);
let setB = new Set(arrayB);
let diff = new Set([...setA].filter(x => !setB.has(x)));
expect([...diff].length).toBe(0);

5
एक सेकंड रुको ... यह केवल जाँचता है कि क्या ए में ऐसे तत्व हैं जो बी नहीं है? यह जाँच नहीं करता है कि B में ऐसे तत्व हैं जो A नहीं करता है। यदि आप कोशिश करते हैं a=[1,2,3]और b=[1,2,3,4]फिर कहते हैं कि वे वही हैं। इसलिए मुझे लगता है कि आपको एक अतिरिक्त जांच की आवश्यकता है जैसेsetA.size === setB.size

0

@Aadit M Shah के उत्तर पर आधारित बहुत मामूली संशोधन:

/**
 * check if two sets are equal in the sense that
 * they have a matching set of values.
 *
 * @param {Set} a 
 * @param {Set} b
 * @returns {Boolean} 
 */
const areSetsEqual = (a, b) => (
        (a.size === b.size) ? 
        [...a].every( value => b.has(value) ) : false
);

यदि किसी और के पास कोई समस्या है जैसा मैंने नवीनतम बैबेल के कुछ क्विक के कारण किया है, तो यहां एक स्पष्ट सशर्त जोड़ना होगा।

(मुझे लगता areहै कि बहुवचन के लिए भी जोर से पढ़ना थोड़ा सहज है)


-1

1) जाँच करें कि क्या आकार बराबर हैं। यदि नहीं, तो वे समान नहीं हैं।

2) ए के प्रत्येक एलिमेंट पर पुनरावृति और उस में जाँच करें कि बी मौजूद है। यदि कोई वापस नहीं आता है unequal

3) यदि उपरोक्त 2 स्थितियाँ विफल होती हैं अर्थात वे समान हैं।

let isEql = (setA, setB) => {
  if (setA.size !== setB.size)
    return false;
  
  setA.forEach((val) => {
    if (!setB.has(val))
      return false;
  });
  return true;
}

let setA = new Set([1, 2, {
  3: 4
}]);
let setB = new Set([2, {
    3: 4
  },
  1
]);

console.log(isEql(setA, setB));

२) विधि २

let isEql = (A, B) => {
  return JSON.stringify([...A].sort()) == JSON.stringify([...B].sort());
}

let res = isEql(new Set([1, 2, {3:4}]), new Set([{3:4},1, 2]));
console.log(res);


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