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).sizea.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 subsetscode {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>