1 數組交集函數——intersection
數組的交集是指包含多個數組中的共同元素的一個數組,求數組的交集就是找出給定數組中的共有元素。
下面實現一個求兩個數組交集的函數。
判斷數組是夠包含指定值,使用Array.indexOf就可以。所以我們可以遍歷第一個參數數組,然后使用Array.indexOf方法檢索第二個參數數組,如果第二個參數數組包含當前項,那么當前項即為兩個數組的交集元素,放入結果數組即可:
var intersection = function(arr1, arr2) { var length = arr1.length; var result = []; var i; for(i = 0; i < length; i++) { if(result.indexOf(arr1[i]) >= 0) continue; else { if(arr2.indexOf(arr1[i]) >= 0) result.push(arr1[i]); } } return result; }
以上代碼實現了求兩個數組交集的功能。
如果涉及到多個數組呢?那就是Underscore的實現方法了。
以下是Underscore的源碼(附注釋):
// Produce an array that contains every item shared between all the // passed-in arrays. //獲取傳入的多個數組的交集,之所以只有一個形參,是因為該函數使用第一個數組參數作為基准。 _.intersection = function (array) { //將要返回的結果數組。 var result = []; //傳入數組的個數。 var argsLength = arguments.length; //遍歷第一個數組參數。 for (var i = 0, length = getLength(array); i < length; i++) { //當前項。 var item = array[i]; //如果結果數組中已有該項,那么直接跳過當前循環,進入下一輪循環中。 if (_.contains(result, item)) continue; var j; //從第二個參數開始,遍歷每一個參數。 for (j = 1; j < argsLength; j++) { //一旦有一個參數數組不包含item,就退出循環。 if (!_.contains(arguments[j], item)) break; } //如果所有參數數組都包含item項,就把item放入result。 if (j === argsLength) result.push(item); } return result; };
可以看到該函數一次接受多個數組,但是只有一個形參(array),該參數表示接收到的第一個數組,Underscore使用它作為參考,遍歷該數組,然后依次判斷剩余參數數組是否包含當前項,如果全部包含則該項為交集元素,推入結果數組當中。
2 數組並集函數——union
數組的並集是指包含指定的多個數組的所有元素的數組,求多個數組的並集即為求一個包含所有數組的所有元素的數組。
這里最直接的實現方法就是遍歷所有數組參數,然后針對數組的每一項,放入到結果數組中(如果已經存在於結果數組中那么久不再添加)。
var union = function() { var arrays = arguments; var length = arguments.length; var result = []; var i; for(i = 0; i < length; i++) { var arr = arrays[i]; var arrLength = arrays[i].length; for(var j = 0; j < arrLength; j++) { if(result.indexOf(arr[j]) < 0) { result.push(arr[j]); } } } return result; }
在閱讀Underscore源碼的時候,感覺它的實現方法十分巧妙。
Underscore中已經有了很多工具方法,所以可以拿來直接使用,比如restArgs、flatten、uniq。為什么強調這幾個方法呢?因為使用這幾個方法就可以實現數組求並集。
我們的union方法是接受多個數組作為參數的,而restArgs可以把多個數組參數合並到一個數組中作為參數;然后通過flatten函數,我們可以把得到的這個數組參數展開,展開之后得到的數組就是包含所有數組參數的所有元素的一個數組了,但是這個數組中有冗余項,我們必須對其進行去重;這時候使用我們的uniq工具函數就可以對其進行去重了。
經過這三個函數的處理,我們得到的數組就是多個數組參數的並集!
Underscore源碼:
// Produce an array that contains the union: each distinct element from all of // the passed-in arrays. _.union = restArgs(function (arrays) { return _.uniq(flatten(arrays, true, true)); });
這樣的實現是不是很簡介大氣?
3 數組差集函數——difference
數組的差集是指由數組A中所有不屬於數組B的元素所組成的一個數組。
直接的實現方法就是遍歷前者,然后判斷每個元素是否屬於后者,如果不屬於,那么就推入結果數組。
簡單實現:
var difference = function(arr1, arr2) { var length = arr1.length; var i; var result = []; for(i = 0; i < length; i++) { if(arr2.indexOf(arr1[i]) < 0) { result.push(arr1[i]); } } return result; }
Underscore的實現(附注釋):
// Take the difference between one array and a number of other arrays. // Only the elements present in just the first array will remain. //數組求差集函數。 //通過restArgs函數把第二個數組開始的所有參數數組合並到一個數組。 _.difference = restArgs(function (array, rest) { //使用flatten展開rest數組。 rest = flatten(rest, true, true); //使用filter函數過濾array數組達到求差集的目的,判斷條件就是value是否屬於rest。 return _.filter(array, function (value) { return !_.contains(rest, value); }); });
更多Underscore源碼解析:GitHub