Hem yaklaşımları için ben fikirlerin benzer olsa da, biraz daha genel amaçlı bir yaklaşım @Cerbrus ve @Kasper MOERCH . İki nesnenin eşit olup olmadığını belirlemek için bir yüklemi kabul eden bir işlev oluşturuyorum (burada $$hashKey
özelliği göz ardı ediyoruz , ancak herhangi bir şey olabilir) ve bu koşula göre iki listenin simetrik farkını hesaplayan bir işlev döndürüyorum:
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);
Erken kaçması bakımından Cerebrus'un yaklaşımına göre (Kasper Moerch'in yaklaşımı gibi) küçük bir avantajı vardır; bir eşleşme bulursa, listenin geri kalanını kontrol etmeye zahmet etmez. curry
Kullanışlı bir işlevim olsaydı, bunu biraz farklı yapardım, ancak bu iyi çalışıyor.
Açıklama
Bir yorum, yeni başlayanlar için daha ayrıntılı bir açıklama istedi. İşte bir deneme.
Aşağıdaki işlevi şunlara aktarıyoruz makeSymmDiffFunc
:
function(x, y) {
return x.value === y.value && x.display === y.display;
}
Bu fonksiyon, iki nesnenin eşit olduğuna nasıl karar verdiğimizdir. Dönen tüm işlevler gibi true
veya false
"yüklem işlevi" olarak adlandırılabilir, ancak bu yalnızca terminolojidir. Ana nokta, makeSymmDiffFunc
iki nesneyi kabul eden ve true
eşit false
olduğunu düşünürsek , yoksa geri dönen bir işlevle yapılandırılmış olmasıdır .
Bunu kullanarak makeSymmDiffFunc
("simetrik fark yaratma işlevi" okuyun) bize yeni bir işlev döndürür:
return function(a, b) {
return complement(pred, a, b).concat(complement(pred, b, a));
};
Aslında kullanacağımız işlev budur. Biz ona iki liste geçiriyoruz ve o birinci değil ikincideki öğeleri buluyor, sonra ikinci listedeki öğeleri bulamıyor ve bu iki listeyi birleştiriyor.
Yine de tekrar baktığımda, kodunuzdan kesinlikle bir ipucu alabilir ve ana işlevi aşağıdakileri kullanarak biraz basitleştirebilirdim 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
yüklemi kullanır ve ilk listesinin öğelerini ikinci değil döndürür. Bu, ayrı bir contains
işleve sahip ilk geçişimden daha basit .
Son olarak, ana işlev, dahili işlevi genel kapsamın dışında tutmak için hemen çağrılan bir işlev ifadesine ( IIFE ) sarılır complement
.
Birkaç yıl sonra güncelleme
ES2015 artık her yerde oldukça yaygın hale geldiğine göre, aynı tekniği çok daha az standart şablonla önereceğim:
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)