ผมใช้วิธีวัตถุประสงค์ทั่วไปเล็กน้อยแม้จะคล้ายกันในความคิดที่จะเข้าใกล้ของทั้งสอง@Cerbrusและ@Kasper Moerch ฉันสร้างฟังก์ชันที่ยอมรับเพรดิเคตเพื่อตรวจสอบว่าวัตถุสองชิ้นเท่ากันหรือไม่ (ที่นี่เราไม่สนใจ $$hashKey
คุณสมบัติ แต่อาจเป็นอะไรก็ได้) และส่งคืนฟังก์ชันที่คำนวณความแตกต่างแบบสมมาตรของสองรายการตามเพรดิเคตนั้น:
a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"}, { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}]
b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}]
var makeSymmDiffFunc = (function() {
var contains = function(pred, a, list) {
var idx = -1, len = list.length;
while (++idx < len) {if (pred(a, list[idx])) {return true;}}
return false;
};
var complement = function(pred, a, b) {
return a.filter(function(elem) {return !contains(pred, elem, b);});
};
return function(pred) {
return function(a, b) {
return complement(pred, a, b).concat(complement(pred, b, a));
};
};
}());
var myDiff = makeSymmDiffFunc(function(x, y) {
return x.value === y.value && x.display === y.display;
});
var result = myDiff(a, b);
มันมีข้อได้เปรียบเล็กน้อยมากกว่าแนวทางของ Cerebrus (เช่นเดียวกับแนวทางของ Kasper Moerch) ที่มันหนีออกมาก่อน หากพบรายการที่ตรงกันก็ไม่ต้องกังวลกับการตรวจสอบส่วนที่เหลือของรายการ ถ้าฉันมีcurry
ฟังก์ชั่นที่มีประโยชน์ฉันจะทำสิ่งนี้ให้แตกต่างออกไปเล็กน้อย แต่ก็ใช้ได้ดี
คำอธิบาย
ความคิดเห็นขอคำอธิบายโดยละเอียดสำหรับผู้เริ่มต้น นี่คือความพยายาม
เราส่งผ่านฟังก์ชันต่อไปนี้ไปที่makeSymmDiffFunc
:
function(x, y) {
return x.value === y.value && x.display === y.display;
}
ฟังก์ชันนี้เป็นวิธีที่เราตัดสินว่าวัตถุสองชิ้นมีค่าเท่ากัน เช่นเดียวกับฟังก์ชันทั้งหมดที่ส่งคืนtrue
หรือfalse
อาจเรียกว่า "ฟังก์ชันเพรดิเคต" แต่นั่นเป็นเพียงคำศัพท์เท่านั้น ประเด็นหลักคือmakeSymmDiffFunc
ถูกกำหนดค่าด้วยฟังก์ชันที่รับวัตถุสองชิ้นและส่งคืนtrue
หากเราพิจารณาว่ามันเท่ากันfalse
ถ้าเราไม่ทำ
เมื่อใช้สิ่งนั้นmakeSymmDiffFunc
(อ่าน "สร้างความแตกต่างแบบสมมาตร") จะส่งคืนฟังก์ชันใหม่ให้เรา:
return function(a, b) {
return complement(pred, a, b).concat(complement(pred, b, a));
};
นี่คือฟังก์ชั่นที่เราจะใช้จริง เราส่งผ่านสองรายการและพบองค์ประกอบในรายการแรกไม่ใช่ในรายการที่สองจากนั้นองค์ประกอบในรายการที่สองไม่ใช่รายการแรกและรวมสองรายการนี้เข้าด้วยกัน
อย่างไรก็ตามเมื่อมองอีกครั้งฉันสามารถใช้คิวจากโค้ดของคุณได้อย่างแน่นอนและทำให้ฟังก์ชันหลักง่ายขึ้นเล็กน้อยโดยใช้some
:
var makeSymmDiffFunc = (function() {
var complement = function(pred, a, b) {
return a.filter(function(x) {
return !b.some(function(y) {return pred(x, y);});
});
};
return function(pred) {
return function(a, b) {
return complement(pred, a, b).concat(complement(pred, b, a));
};
};
}());
complement
ใช้เพรดิเคตและส่งคืนองค์ประกอบของรายการแรกไม่ใช่ในรายการที่สอง วิธีนี้ง่ายกว่าพาสแรกของฉันที่มีcontains
ฟังก์ชันแยกต่างหาก
สุดท้ายฟังก์ชันหลักจะรวมอยู่ในนิพจน์ฟังก์ชันที่เรียกใช้ทันที ( IIFE ) เพื่อป้องกันไม่ให้complement
ฟังก์ชันภายในอยู่นอกขอบเขตส่วนกลาง
อัปเดตไม่กี่ปีต่อมา
ตอนนี้ ES2015 เริ่มแพร่หลายไปแล้วฉันขอแนะนำเทคนิคเดียวกันนี้โดยมีแผ่นสำเร็จรูปน้อยกว่ามาก:
const diffBy = (pred) => (a, b) => a.filter(x => !b.some(y => pred(x, y)))
const makeSymmDiffFunc = (pred) => (a, b) => diffBy(pred)(a, b).concat(diffBy(pred)(b, a))
const myDiff = makeSymmDiffFunc((x, y) => x.value === y.value && x.display === y.display)
const result = myDiff(a, b)