使用 lodash 的 isEqual() 排除比较中的一些属性
Exclude some properties in comparison using isEqual() of lodash
我正在使用 _.isEqual 来比较 2 个对象数组(例如:每个对象有 10 个属性),并且工作正常。
现在有 2 个属性(创建和删除)我不需要参与比较。
示例:
var obj1 = {name: "James", age: 17, creation: "13-02-2016", deletion: "13-04-2016"}
var obj2 = {name: "Maria", age: 17, creation: "13-02-2016", deletion: "13-04-2016"}
// lodash method...
_.isEqual(firstArray, secondArray)
您可以 map 将您的数组转换为 "cleaned" 数组,然后比较它们。
// Create a function, to do some cleaning of the objects.
var clean = function(obj) {
return {name: obj.name, age: obj.age};
};
// Create two new arrays, which are mapped, 'cleaned' copies of the original arrays.
var array1 = firstArray.map(clean);
var array2 = secondArray.map(clean);
// Compare the new arrays.
_.isEqual(array1, array2);
这有一个缺点,即如果对象需要任何新属性,clean
函数将需要更新。可以对其进行编辑,以便删除两个不需要的属性。
我看到两个选项。
1) 为不包含创建或日期的每个对象制作第二个副本。
2) 遍历所有属性,假设您确定它们都具有相同的属性,请尝试这样的操作。
var x ={}
var y ={}
for (var property in x) {
if(property!="creation" || property!="deletion"){
if (x.hasOwnProperty(property)) {
compare(x[property], y[property])
}
}
}
其中 compare() 是一些简单的字符串或对象比较。如果您确定一个或两个对象的某些属性,您可以进一步简化此代码,但这在大多数情况下应该有效。
您可以使用 omit() 删除对象中的特定属性。
var result = _.isEqual(
_.omit(obj1, ['creation', 'deletion']),
_.omit(obj2, ['creation', 'deletion'])
);
var obj1 = {
name: "James",
age: 17,
creation: "13-02-2016",
deletion: "13-04-2016"
};
var obj2 = {
name: "Maria",
age: 17,
creation: "13-02-2016",
deletion: "13-04-2016"
};
var result = _.isEqual(
_.omit(obj1, ['creation', 'deletion']),
_.omit(obj2, ['creation', 'deletion'])
);
console.log(result);
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>
@ryeballar 的回答对大对象来说不是很好,因为每次比较时都会创建每个对象的深层副本。
最好用isEqualWith
。例如,要忽略 "creation" 和 "deletion" 属性中的差异:
var result = _.isEqualWith(obj1, obj2, (value1, value2, key) => {
return key === "creation" || key === "deletion" ? true : undefined;
});
编辑(评论中指出的重要警告): 如果对象有不同数量的键,那么 isEqualWith
认为它们是不同的,不管你的是什么定制器会。因此,如果您想忽略可选的 属性.,请勿使用此方法,而是考虑使用 _.isMatch()
、_.isMatchWith()
或@ryeballar 的 _.omit()
方法。
请注意,如果您正在为 ES5 及更早版本编写代码,则必须将箭头语法 (() => {
) 替换为函数语法 (function() {
)
_.omit
创建对象的 深拷贝 。如果你只需要排除根属性,最好创建 浅拷贝 使用,例如,解构赋值:
const x = { a: 4, b: [1, 2], c: 'foo' }
const y = { a: 4, b: [1, 2], c: 'bar' }
const { c: xC, ...xWithoutC } = x
const { c: yC, ...yWithoutC } = y
_.isEqual(xWithoutC, yWithoutC) // true
xWithoutC.b === x.b // true, would be false if you use _.omit
最好的方法 根本不创建副本 (TypeScript):
function deepEqual(
x?: object | null,
y?: object | null,
ignoreRootProps?: Set<string>
) {
if (x == null || y == null) return x === y
const keys = Object.keys(x)
if (!_.isEqual(keys, Object.keys(y)) return false
for (let key of keys) {
if (ignoreRootProps && ignoreRootProps.has(key)) continue
if (!_.isEqual(x[key], y[key])) return false
}
return true
}
我的最终解决方案需要进行全面比较,忽略可选的 属性,因此上述解决方案不起作用。
在与 isEqual
:
进行比较之前,我使用浅克隆从每个对象中删除了我想忽略的键
const equalIgnoring = (newItems, originalItems) => newItems.length === originalItems.length
&& newItems.every((newItem, index) => {
const rest1 = { ...newItem };
delete rest1.creation;
delete rest1.deletion;
const rest2 = { ...originalItems[index] };
delete rest2.creation;
delete rest2.deletion;
return isEqual(rest1, rest2);
});
如果您想检查数组中每个项目的子集,这可行:
const equalIgnoringExtraKeys = (fullObjs, partialObjs) =>
fullObjs.length === partialObjs.length
&& fullObjs.every((fullObj, index) => isMatch(fullObj, partialObjs[index]));
如果您还想忽略特定的 属性 并检查子集:
const subsetIgnoringKeys = (fullObjs, partialObjs) =>
fullObjs.length === partialObjs.length
&& fullObjs.every((fullObj, index) => isMatchWith(
fullObj,
partialObjs[index],
(objValue, srcValue, key, object, source) => {
if (["creation", "deletion"].includes(key)) {
return true;
}
return undefined;
}
));
我正在使用 _.isEqual 来比较 2 个对象数组(例如:每个对象有 10 个属性),并且工作正常。
现在有 2 个属性(创建和删除)我不需要参与比较。
示例:
var obj1 = {name: "James", age: 17, creation: "13-02-2016", deletion: "13-04-2016"}
var obj2 = {name: "Maria", age: 17, creation: "13-02-2016", deletion: "13-04-2016"}
// lodash method...
_.isEqual(firstArray, secondArray)
您可以 map 将您的数组转换为 "cleaned" 数组,然后比较它们。
// Create a function, to do some cleaning of the objects.
var clean = function(obj) {
return {name: obj.name, age: obj.age};
};
// Create two new arrays, which are mapped, 'cleaned' copies of the original arrays.
var array1 = firstArray.map(clean);
var array2 = secondArray.map(clean);
// Compare the new arrays.
_.isEqual(array1, array2);
这有一个缺点,即如果对象需要任何新属性,clean
函数将需要更新。可以对其进行编辑,以便删除两个不需要的属性。
我看到两个选项。
1) 为不包含创建或日期的每个对象制作第二个副本。
2) 遍历所有属性,假设您确定它们都具有相同的属性,请尝试这样的操作。
var x ={}
var y ={}
for (var property in x) {
if(property!="creation" || property!="deletion"){
if (x.hasOwnProperty(property)) {
compare(x[property], y[property])
}
}
}
其中 compare() 是一些简单的字符串或对象比较。如果您确定一个或两个对象的某些属性,您可以进一步简化此代码,但这在大多数情况下应该有效。
您可以使用 omit() 删除对象中的特定属性。
var result = _.isEqual(
_.omit(obj1, ['creation', 'deletion']),
_.omit(obj2, ['creation', 'deletion'])
);
var obj1 = {
name: "James",
age: 17,
creation: "13-02-2016",
deletion: "13-04-2016"
};
var obj2 = {
name: "Maria",
age: 17,
creation: "13-02-2016",
deletion: "13-04-2016"
};
var result = _.isEqual(
_.omit(obj1, ['creation', 'deletion']),
_.omit(obj2, ['creation', 'deletion'])
);
console.log(result);
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>
@ryeballar 的回答对大对象来说不是很好,因为每次比较时都会创建每个对象的深层副本。
最好用isEqualWith
。例如,要忽略 "creation" 和 "deletion" 属性中的差异:
var result = _.isEqualWith(obj1, obj2, (value1, value2, key) => {
return key === "creation" || key === "deletion" ? true : undefined;
});
编辑(评论中指出的重要警告): 如果对象有不同数量的键,那么 isEqualWith
认为它们是不同的,不管你的是什么定制器会。因此,如果您想忽略可选的 属性.,请勿使用此方法,而是考虑使用 _.isMatch()
、_.isMatchWith()
或@ryeballar 的 _.omit()
方法。
请注意,如果您正在为 ES5 及更早版本编写代码,则必须将箭头语法 (() => {
) 替换为函数语法 (function() {
)
_.omit
创建对象的 深拷贝 。如果你只需要排除根属性,最好创建 浅拷贝 使用,例如,解构赋值:
const x = { a: 4, b: [1, 2], c: 'foo' }
const y = { a: 4, b: [1, 2], c: 'bar' }
const { c: xC, ...xWithoutC } = x
const { c: yC, ...yWithoutC } = y
_.isEqual(xWithoutC, yWithoutC) // true
xWithoutC.b === x.b // true, would be false if you use _.omit
最好的方法 根本不创建副本 (TypeScript):
function deepEqual(
x?: object | null,
y?: object | null,
ignoreRootProps?: Set<string>
) {
if (x == null || y == null) return x === y
const keys = Object.keys(x)
if (!_.isEqual(keys, Object.keys(y)) return false
for (let key of keys) {
if (ignoreRootProps && ignoreRootProps.has(key)) continue
if (!_.isEqual(x[key], y[key])) return false
}
return true
}
我的最终解决方案需要进行全面比较,忽略可选的 属性,因此上述解决方案不起作用。
在与 isEqual
:
const equalIgnoring = (newItems, originalItems) => newItems.length === originalItems.length
&& newItems.every((newItem, index) => {
const rest1 = { ...newItem };
delete rest1.creation;
delete rest1.deletion;
const rest2 = { ...originalItems[index] };
delete rest2.creation;
delete rest2.deletion;
return isEqual(rest1, rest2);
});
如果您想检查数组中每个项目的子集,这可行:
const equalIgnoringExtraKeys = (fullObjs, partialObjs) =>
fullObjs.length === partialObjs.length
&& fullObjs.every((fullObj, index) => isMatch(fullObj, partialObjs[index]));
如果您还想忽略特定的 属性 并检查子集:
const subsetIgnoringKeys = (fullObjs, partialObjs) =>
fullObjs.length === partialObjs.length
&& fullObjs.every((fullObj, index) => isMatchWith(
fullObj,
partialObjs[index],
(objValue, srcValue, key, object, source) => {
if (["creation", "deletion"].includes(key)) {
return true;
}
return undefined;
}
));