利用Underscore求數組的交集、並集和差集

1 數組交集函數——intersection

數組的交集是指包含多個數組中的共同元素的一個數組,求數組的交集就是找出給定數組中的共有元素。javascript

下面實現一個求兩個數組交集的函數。java

判斷數組是夠包含指定值,使用Array.indexOf就能夠。因此咱們能夠遍歷第一個參數數組,而後使用Array.indexOf方法檢索第二個參數數組,若是第二個參數數組包含當前項,那麼當前項即爲兩個數組的交集元素,放入結果數組便可:git

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;
}

  

以上代碼實現了求兩個數組交集的功能。github

若是涉及到多個數組呢?那就是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

數組的並集是指包含指定的多個數組的全部元素的數組,求多個數組的並集即爲求一個包含全部數組的全部元素的數組。spa

這裏最直接的實現方法就是遍歷全部數組參數,而後針對數組的每一項,放入到結果數組中(若是已經存在於結果數組中那麼久再也不添加)。rest

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源碼的時候,感受它的實現方法十分巧妙。code

Underscore中已經有了不少工具方法,因此能夠拿來直接使用,好比restArgsflattenuniq。爲何強調這幾個方法呢?由於使用這幾個方法就能夠實現數組求並集。

咱們的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

相關文章
相關標籤/搜索