ค้นหาเว็บไซต์

javascript - การเปรียบเทียบชุด ECMA6 เพื่อความเท่าเทียม


คุณเปรียบเทียบเซ็ตของ JavaScript สองชุดอย่างไร? ผมลองใช้ == และ === แต่ทั้งสองให้ค่า false

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

สองชุดนี้เทียบเท่ากัน เพราะตามคำนิยาม ชุดไม่มีลำดับ (อย่างน้อยก็ไม่ใช่มักจะ) ฉันได้ดูเอกสารสำหรับ Set บน MDN แล้วแต่ไม่พบอะไรที่มีประโยชน์ มีใครรู้วิธีทำไหม?

คำตอบ #1

ลองอันนี้:

const eqSet = (xs, ys) =>
    xs.size === ys.size &&
    [...xs].every((x) => ys.has(x));

const ws = new Set([1, 2, 3]);
const xs = new Set([1, 3, 2]);
const ys = new Set([1, 2, 4]);
const zs = new Set([1, 2, 3, 4]);

console.log(eqSet(ws, xs)); // true
console.log(eqSet(ws, ys)); // false
console.log(eqSet(ws, zs)); // false

คำตอบ #2

คุณยังสามารถลอง:

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

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

console.log(areSetsEqual(a,b)) 

คำตอบ #3

lodash มี _.isEqual() ซึ่งทำการเปรียบเทียบเชิงลึก นี่สะดวกมากถ้าคุณไม่ต้องการเขียนเอง ตั้งแต่ lodash 4 เป็นต้นมา _.isEqual() สามารถเปรียบเทียบ Sets ได้อย่างถูกต้อง

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

คำตอบ #4

คุณสามารถทำดังต่อไปนี้ได้:

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

// option 1
console.log(a.size === b.size && new Set([...a, ...b]).size === a.size)

// option 2
console.log([...a].sort().join() === [...b].sort().join())

คำตอบ #5

ฉันเชื่อว่านี่คือเวอร์ชันที่มีประสิทธิภาพที่สุดเพราะมันไม่ได้สร้างอาร์เรย์ใหม่ มันใช้ตัววนซ้ำของตัว Set เอง:

function isEqualSets(a, b) {
  if (a === b) return true;
  if (a.size !== b.size) return false;
  for (const value of a) if (!b.has(value)) return false;
  return true;
}

อัปเดต - Safari ได้เพิ่มเมธอด Set แบบทดลองใช้งานมาพร้อมในตัว ดังนั้นเมื่อสิ่งนี้ถูกใช้งานในเบราว์เซอร์ทั้งหมด เราสามารถทำได้ดังนี้:

function isEqualSets(a, b) {
  return a.size === b.size && a.size === a.union(b).size;
}

คำตอบ #6

ณ ปี 2024 ได้มีการเพิ่มวิธีการใหม่ใน Set ที่ทำให้เรื่องนี้ง่ายขึ้นมาก (พวกมันไม่ได้รวมการตรวจสอบความเท่าเทียมกันเฉพาะ; @Inkling ชี้ให้เห็นการสนทนาเกี่ยวกับการตัดสินใจนั้นที่นี่)

วิธีการเหล่านี้รองรับในเบราว์เซอร์และ Node.js แทบทั้งหมด และอนุญาตให้คุณเปรียบเทียบสองชุด (a และ b) เพื่อความเท่าเทียมกันด้วยนิพจน์เช่น:

  • a.size == b.size && a.size == a.union(b).size
  • a.isSupersetOf(b) && a.isSubsetOf(b)
  • (สั้นกว่าแต่ในความเห็นของฉันชัดเจนน้อยกว่า) a.symmetricDifference(b).size == 0
  • a.size === b.size && a.isSubsetOf(b) (เสนอเป็นวิธีแก้ชั่วคราวเมื่อมีคนแนะนำให้เพิ่ม .equals() เข้าไปใน API)

... อันไหนที่อ่านง่ายที่สุดสำหรับคุณ เว้นแต่ว่าคุณกำลังใช้ชุดข้อมูลขนาดใหญ่ ผมยังไม่ได้ทดสอบประสิทธิภาพของพวกมันเลย

คำตอบ #7

ไม่มีวิธีแก้ปัญหาเหล่านี้ใดที่ทำให้ฟังก์ชันที่คาดหวังกลับมาสู่โครงสร้างข้อมูล เช่น set of sets ในสภาพปัจจุบัน Set ของ Javascript ไม่เป็นประโยชน์สำหรับวัตถุประสงค์นี้เพราะชุดย่อยที่ซ้อนกันจะมีชุดย่อยซ้ำ ซึ่ง Javascript มองต่างออกไปอย่างผิดพลาด วิธีแก้ปัญหาเดียวที่ฉันคิดได้คือการแปลงแต่ละชุดย่อยเป็น Array, จัดเรียงมัน จากนั้นเข้ารหัสเป็น String (เช่น 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>

บทความที่เกี่ยวข้อง