如何在Lodash的isEqualWith中将缺失和未定义的属性视为等效

时间:2019-09-10 16:27:42

标签: javascript lodash equality

我正在为Lodash的_.isEqualWith使用自定义比较功能。我想要一个可以正常工作的函数:

const comparisonFunc = /* ...TBC... */

// Should be true:
_.isEqualWith({ a: undefined }, { }, comparisonFunc);

// Should still be false, as normal:
_.isEqualWith({ a: undefined }, { a: 123 }, comparisonFunc);

// Should still be false, as normal:
_.isEqualWith([undefined], [ ], comparisonFunc);

即对于比较中的任何对象(递归),应将设置为undefined的属性视为不存在。

4 个答案:

答案 0 :(得分:0)

这不是我想要的那么简单,但是我找到了解决方案:

const comparisonFunc = (a, b) => {
    if (_.isArray(a) || _.isArray(b)) return;
    if (!_.isObject(a) || !_.isObject(b)) return;

    if (!_.includes(a, undefined) && !_.includes(b, undefined)) return;

    // Call recursively, after filtering all undefined properties
    return _.isEqualWith(
        _.omitBy(a, (value) => value === undefined),
        _.omitBy(b, (value) => value === undefined),
        comparisonFunc
    );
}


// Should be true:
_.isEqualWith({ a: undefined }, { }, comparisonFunc); // = true

// Should still be false, as normal:
_.isEqualWith({ a: undefined }, { a: 123 }, comparisonFunc); // = false

// Should still be false, as normal:
_.isEqualWith([undefined], [ ], comparisonFunc); // = false

很高兴接受其他答案:-)

答案 1 :(得分:0)

您只需检查Wheather是一个数组还是对象,并相应地过滤undefined个成员,然后递归调用即可。

const comp = (a, b) => {
  var A, B,
      fn = v => !_.isUndefined(v),
      filter = _.isArray(a)  ? _.filter : _.pickBy;
	if (_.isObject(a)) {
		A = filter(a, fn)
		B = filter(b, fn)
	} else { return _.isEqual(a, b); } 

	if (_.keys(a).length === _.keys(A).length && _.keys(b).length === _.keys(B).length) {return}
	return _.isEqualWith(A, B, comp);
};

var a1 = [10, 10, undefined, undefined, 10],
    a2 = [undefined, undefined, 10, undefined, 10, undefined, 10],
    o1 = {x: 10, y:undefined, z: 20, v: a1}
    o2 = {x: 10, z: 20, v: a2};

console.log('a1 with a2: ', _.isEqualWith(a1, a2, comp));
console.log('o1 with o2: ', _.isEqualWith(o1, o2, comp));
console.log('a1 with o2: ', _.isEqualWith(a1, o2, comp));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

检查密钥长度和return语句是否可以确定我们必须在内部遍历(在上次迭代中删除了未定义的值)还是需要再次遍历(在此迭代中删除了未定义的值)

答案 2 :(得分:0)

与 Tim Perry 的回答相同,仅使用 TypeScript 和 lodash/fp


function matchMissingWithUndefined(a: {}, b: {}) {
  const hasUndefined = _.includes(undefined);
  if (_.isPlainObject(a) && _.isPlainObject(b) && (hasUndefined(a) || hasUndefined(b))) {
    const onlyDefined = _.omitBy((value) => value === undefined);
    return _.isEqualWith(matchMissingWithUndefined, onlyDefined(a), onlyDefined(b));
  }
}

_.isEqualWith(matchMissingWithUndefined, { a: undefined }, { }); // true

答案 3 :(得分:0)

在省略 null 值后,我们应该以某种方式绕过对 customizer 的初始调用,而无需再次检查对象是否没有 includes null 值。

我为此目的发明了某种不错的自行车:

const compareWithoutNullProperties = (a: any, b: any) =>
  isPlainObject(a) && isPlainObject(b)
    ? isEqualWith(
      omitBy(a, (value) => value == null),
      omitBy(b, (value) => value == null),
      (a: any, b: any, key?: number | string | symbol): boolean | undefined =>
        // Next initial call should be ignored.
        key != null ? compareWithoutNullProperties(a, b) : undefined,
    )
    : undefined;

const isEqualWithoutNullProperties = (a: any, b: any) =>
  isEqualWith(a, b, compareWithoutNullProperties);

返回 true 的测试:

isEqualWithoutNullProperties({ a: undefined }, {});
isEqualWithoutNullProperties({ a: null }, {});
isEqualWithoutNullProperties([{ a: undefined }], [{}]);
isEqualWithoutNullProperties([{ a: null }], [{}]);
isEqualWithoutNullProperties({ a: { a: undefined } }, { a: {} });
isEqualWithoutNullProperties({ a: { a: null } }, { a: {} });
isEqualWithoutNullProperties({ a: [{ a: undefined }] }, { a: [{}] });
isEqualWithoutNullProperties({ a: [{ a: null }] }, { a: [{}] });

返回 false 的测试:

isEqualWithoutNullProperties([undefined], []);
isEqualWithoutNullProperties([null], []);
isEqualWithoutNullProperties([undefined], [1]);
isEqualWithoutNullProperties([null], [1]);
isEqualWithoutNullProperties({ a: undefined }, { a: 1 });
isEqualWithoutNullProperties({ a: null }, { a: 1 });
isEqualWithoutNullProperties([{ a: undefined }], [{ a: 1 }]);
isEqualWithoutNullProperties([{ a: null }], [{ a: 1 }]);
isEqualWithoutNullProperties({ a: { a: undefined } }, { a: { a: 1 } });
isEqualWithoutNullProperties({ a: { a: null } }, { a: { a: 1 } });
isEqualWithoutNullProperties({ a: [{ a: undefined }] }, { a: [{ a: 1 }] });
isEqualWithoutNullProperties({ a: [{ a: null }] }, { a: [{ a: 1 }] });