本篇继续分析下 xor
家族的方法,xor
方法的主要目的就是实现异或,也就是对称差(symmetric difference)。包括xor
、xorBy
、xorWith
及核心方法 baseXor
。
对应源码分析已推到 github
仓库: https://github.com/MageeLin/lodash-source-code-analysis
原理
数学原理
该方法的数学原理其实很简单,两个集合 a
和 b
求对称差的换算方式如下:
a ⊕ b = (a ∧ ¬b) ∨ (¬a ∧ b)
同理,三个集合 a
、b
、c
求对称差的换算方式如下:
a ⊕ b ⊕ c = ((a ∧ ¬b) ∨ (a ∧ ¬c)) ∨ ((b ∧ ¬a) ∨ (b ∧ ¬c)) ∨ ((c ∧ ¬a) ∨ (c ∧ ¬b))
以此类推,n 个集合求对称差时,都可以分成两步,第一步将每一个集合都与所有其他的集合的非
求交集,第二步将交集全都并
起来。
在 lodash 实现时,第一步将所有 array
都与其他 array
一起 baseDifference
实现 交集
,第二步 baseFlatten
展平一层且 baseUniq
去重实现 并
。
依赖路径图
xor
家族方法的依赖路径图如下所示:

只需要注意左侧的主要依赖,右侧的依赖在之前的文章中已经分析过。
流程图
xor
家族方法实现时的主要流程图如下所示:

依赖的基础方法
baseXor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import baseDifference from './baseDifference.js'; import baseFlatten from './baseFlatten.js'; import baseUniq from './baseUniq.js';
function baseXor(arrays, iteratee, comparator) { const length = arrays.length; if (length < 2) { return length ? baseUniq(arrays[0]) : []; } let index = -1; const result = new Array(length);
while (++index < length) { const array = arrays[index]; let othIndex = -1;
while (++othIndex < length) { if (othIndex != index) { result[index] = baseDifference( result[index] || array, arrays[othIndex], iteratee, comparator ); } } } return baseUniq(baseFlatten(result, 1), iteratee, comparator); }
export default baseXor;
|
xor 家族
xor
家族都是调用了 baseXor
核心方法。
xor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import baseXor from './.internal/baseXor.js'; import isArrayLikeObject from './isArrayLikeObject.js';
function xor(...arrays) { return baseXor(arrays.filter(isArrayLikeObject)); }
export default xor;
|
xorBy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import baseXor from './.internal/baseXor.js'; import isArrayLikeObject from './isArrayLikeObject.js'; import last from './last.js';
function xorBy(...arrays) { let iteratee = last(arrays); if (isArrayLikeObject(iteratee)) { iteratee = undefined; } return baseXor(arrays.filter(isArrayLikeObject), iteratee); }
export default xorBy;
|
xorWith
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import baseXor from './.internal/baseXor.js'; import isArrayLikeObject from './isArrayLikeObject.js'; import last from './last.js';
function xorWith(...arrays) { let comparator = last(arrays); comparator = typeof comparator === 'function' ? comparator : undefined; return baseXor(arrays.filter(isArrayLikeObject), undefined, comparator); }
export default xorWith;
|
原生实现
原生实现时可以更简单,利用对称差的结合律:
a ⊕ b ⊕ c ⊕ d = ((a ⊕ b) ⊕ c) ⊕ d
直接可以用 reduce
,用之前的对称差结果
和下一个数组
求对称差
即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| function xor(...arrays) { let result = arrays.reduce((arrayAcc, arrayCur) => { let resultCur = [];
arrayAcc.forEach((item) => { if (arrayCur.indexOf(item) < 0) { resultCur.push(item); } });
arrayCur.forEach((item) => { if (arrayAcc.indexOf(item) < 0) { resultCur.push(item); } });
return resultCur; }); return [...new Set(result)]; }
|
前端记事本,不定期更新,欢迎关注!