Tôi thực hiện một cách tiếp cận có mục đích chung hơn một chút, mặc dù ý tưởng tương tự như các cách tiếp cận của cả @Cerbrus và @Kasper Moerch . Tôi tạo một hàm chấp nhận một vị từ để xác định xem hai đối tượng có bằng nhau hay không (ở đây chúng tôi bỏ qua thuộc $$hashKey
tính, nhưng nó có thể là bất kỳ thứ gì) và trả về một hàm tính toán sự khác biệt đối xứng của hai danh sách dựa trên vị từ đó:
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); //=> {value="a63a6f77-c637-454e-abf2-dfb9b543af6c", display="Ryan"}
Nó có một lợi thế nhỏ so với cách tiếp cận của Cerebrus (cũng như cách tiếp cận của Kasper Moerch) ở chỗ nó thoát sớm; nếu nó tìm thấy một kết quả phù hợp, nó sẽ không bận tâm kiểm tra phần còn lại của danh sách. Nếu tôi có một curry
chức năng hữu ích, tôi sẽ làm điều này hơi khác một chút, nhưng điều này hoạt động tốt.
Giải trình
Một bình luận yêu cầu giải thích chi tiết hơn cho người mới bắt đầu. Đây là một nỗ lực.
Chúng tôi chuyển hàm sau cho makeSymmDiffFunc
:
function(x, y) {
return x.value === y.value && x.display === y.display;
}
Hàm này là cách chúng ta quyết định rằng hai đối tượng bằng nhau. Giống như tất cả các hàm trả về true
hoặc false
, nó có thể được gọi là "hàm vị từ", nhưng đó chỉ là thuật ngữ. Điểm chính là nó makeSymmDiffFunc
được cấu hình với một hàm chấp nhận hai đối tượng và trả về true
nếu chúng ta coi chúng bằng nhau, false
nếu chúng ta không.
Sử dụng hàm đó, makeSymmDiffFunc
(đọc "tạo hàm khác biệt đối xứng") trả về cho chúng ta một hàm mới:
return function(a, b) {
return complement(pred, a, b).concat(complement(pred, b, a));
};
Đây là chức năng chúng tôi thực sự sẽ sử dụng. Chúng tôi chuyển cho nó hai danh sách và nó tìm các phần tử trong danh sách đầu tiên không có trong danh sách thứ hai, sau đó tìm các phần tử trong danh sách thứ hai không có trong danh sách đầu tiên và kết hợp hai danh sách này.
Tuy nhiên, nhìn lại nó một lần nữa, tôi chắc chắn có thể đã lấy một gợi ý từ mã của bạn và đơn giản hóa hàm chính một chút bằng cách sử dụng 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
sử dụng vị từ và trả về các phần tử của danh sách đầu tiên không có trong danh sách thứ hai. Điều này đơn giản hơn lần vượt qua đầu tiên của tôi với một contains
hàm riêng biệt .
Cuối cùng, hàm chính được bao bọc trong một biểu thức hàm được gọi ngay lập tức ( IIFE ) để giữ cho complement
hàm bên trong nằm ngoài phạm vi toàn cục.
Cập nhật, một vài năm sau
Bây giờ ES2015 đã trở nên khá phổ biến, tôi sẽ đề xuất kỹ thuật tương tự, với ít bản ghi âm hơn:
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)
//=> {value="a63a6f77-c637-454e-abf2-dfb9b543af6c", display="Ryan"}