题外话:
我本来打算百度的,毕竟自己写太烦。但是找到的好多代码,都会出现各种问题。
比如:
数组A【0,0,0,0,1,1,1,1,1】,数组B【2,2,‘2’,4,4,4】,求它们的交集,会返回【0,1,2,4】。或者,不支持字符串等等。
原因:
没有去重,0 被存储在哈希对象中,被显示出现 4 次。又因为,是通过判断元素在哈希对象中出现次数是否等于 arguments.length 来进行判断它是否为交集元素的。所以一旦数组出现重复项或者稍微复杂一点的数据(排除引用类型数据),就会出现很多瑕疵,不够严谨。所以我才动手改良了下。
去重后,每个元素只会在当前数组中出现一次,那么就可以通过标记该元素是否出现的次数等于数组数量,来进行判断是否为交集元素,这样就不会出现因为重复项导致结果错误的现象。
性能可能没那么好,但起码准确性较高。
-
注意:
- 1. 不支持引用类型数据(存在引用类型数据的数组应该不需要求交集吧);
- 2. 不同数据类型但同值的数据,会识别为相同的元素,类似相等运算符;
- 3. 在转换过程中,阻止了 null 转为 0,true 转为 1,false 转为 0;
- 4. NaN 与 'NaN' 或者它本身,都进行了处理,使它们能够“相等”;
- 5. 关于返回的交集数组的元素数据类型:除非只能为字符串,否则都不会以字符串类型返回
关于 NaN 的处理:
思路:普通排序、数字升序、去重、存储相同元素
/**
* 含 forEach()、map() 不被低版本 IE 支持
*
* [intersect 用于获取数组间的交集]
* @return {[array]} [返回交集数组]
*
* 注意:
* 1. undefined、'undefined' 等(字符串与原值)不会被区分,归为相同值;
* 2. NaN 与 NaN、'NaN' 也进行了处理,使之能够被去重、求交集;
* 3. 关于字符串 'undefined' 与 undefined 数据为何相等,因为 value in object 不区分该"属性名"是否带有引号;
* 4. 所以 1、'1' 也是相同的,虽然一个是 string,一个是 number,但它们数值相同;
* 5. 除了特殊值的字符串形式,其余字符串都原样返回;
* 6. 由于使用浅拷贝,且无法(或困难)将引用类型数据进行去重处理(object就特烦),所以不支持含引用类型元素的数组;
*/
Array.intersect = function() {
var hash = {}, // 哈希对象
result = [], // 返回的结果
arr = []; // 去重后的数组
/**
* 去重,避免因数组内的重复项而影响结果【对原数据类型与字符串不进行区分,如:undefined 与 'undefined' 相同】
*
* @param {[type]} arg [由外层传递进来的 arguments 参数]
* @return {[none]} [不返回值,虽然对数组进行去重操作,但不会影响原数组(浅拷贝)]
*/
;(function(arg) {
for (var i = 0; i < arg.length; i++) {
for (var j = 0; j < arg[i].length; j++) {
var n = 1, // 第一项不变动
count = 0; // 从 0 开始计数
// 浅拷贝【避免影响原数据】,先正常排序(针对字符串),再升序排序(针对数字)
arr[i] = arg[i].map(function(ele, idnex, arr) {
return ele;
}).sort().sort(function(prev, cur) {
return prev - cur;
});
// 去重,ele:当前元素、index:当前下标、arr:调用 forEach() 的当前数组
arr[i].forEach(function(ele, index, arr) {
if (index > 0) {
// 转为字符串再进行判断,将 string 1 与 number 1 视为相等元素
if (arr[index]+'' !== arr[index-1]+'') {
arr[n++] = arr[index];
} else {
count++;
}
}
});
arr[i].length -= count; // 移除重复项后,需要减去对应长度
}
}
})(arguments);
// console.log(arr); // 将参数数组,去重后并排序后,返回的结果
// 获取去重数据后,再进行交集处理
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[i].length; j++) {
var item = arr[i][j];
if (!hash[item]) { // 在哈希对象找不到该项,则添加,并初始计数 1
hash[item] = 1;
} else { // 若能找到,则递增计数
hash[item]++;
if (hash[item] === arguments.length) { // 去重后,若该项计数次数等于 数组数量 ,即表示该项为交集元素
/**
* 1. 特殊值以原数据类型返回,如:'undefined' 会以 undefined 返回;
* 2. string 数字均会以 number 返回;
* 3. 其余 string 还是以 string 返回;
* 4. 如此一来,返回的交集数组的元素,能不以字符串显示就不以字符串显示;
* 5. 不必纠结 'undefined' 是否字为符串,把它归为 undefined 就好了;
* 6. 同数组的 NaN 或 'NaN' 也能被去重,并且不同数组的 NaN 或 'NaN' 也能纳入交集数组
*/
// 用于匹配特殊值
var r_obj = {
'true': '用',
'false': '于',
'null': '匹',
'undefined': '配',
'NaN': '。'
};
if (item in r_obj) { // 如此,'undefined' 与 undefined 便会被识别为相同值
if (item === true || item === 'true') {
result.push(true);
} else if (item === false || item === 'false') {
result.push(false);
} else if (item === null || item === 'null') {
result.push(null);
} else if (item === undefined || item === 'undefined') {
result.push(undefined);
} else if (item+'' === 'NaN') {
result.push(NaN);
}
} else if (!isNaN(item)) { // 数字都会以 number 显示
result.push(item/1);
} else if (isNaN(item)) { // 其余字符串则不变
result.push(item);
};
};
}
}
}
console.log(hash); // 返回哈希对象,查看去重后各项元素出现的次数
// 输出升序结果数组
return result.sort(function(a, b) {
return a - b;
});
};
兼容:for 模仿 forEach()、concat() 替代 map()
/**
* 使用 for 模仿 forEach(),concat() 替代 map(),兼容低版本 IE
*/
Array.intersect = function() {
var hash = {}, // 哈希对象
result = [], // 返回的结果
arr = []; // 去重后的数组
// 去重
;(function(arg) {
for (var i = 0; i < arg.length; i++) {
for (var j = 0; j < arg[i].length; j++) {
// 浅拷贝【避免影响原数据】
arr[i] = arg[i].concat([]);
// 先正常排序(针对字符串),再升序排序(针对数字)
arr[i].sort().sort(function(prev, cur) {
return prev - cur;
});
/**
* [for 去重处理,模仿 forEach,用于兼容]
* @param {Number} k [遍历参数数组每项元素]
* @param {Number} n [第一项不变动,然后遇到相邻重复项都会跳过,重新定义数组]
* @param {[type]} count [计数器,计算重复项目的数量,最后以原数组长度减去该数量,得到去重后的数组的长度]
* @return {[none]} [去重操作,无返回]
*/
for (var k = 0, n = 1, count = 0; k < arr[i].length; k++) {
if (k > 0) {
if (arr[i][k]+'' !== arr[i][k-1]+'') {
arr[i][n++] = arr[i][k]
} else {
count++;
}
}
}
arr[i].length -= count;
}
}
})(arguments);
// console.log(arr); // 将参数数组,去重后并排序后,返回的结果
// 获取去重数据后,再进行交集处理
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[i].length; j++) {
var item = arr[i][j];
if (!hash[item]) { // 在哈希对象找不到该项,则添加,并初始计数 1
hash[item] = 1;
} else { // 若能找到,则递增计数
hash[item]++;
if (hash[item] === arguments.length) { // 去重后,若该项计数次数等于 数组数量 ,即表示该项为交集元素
/**
* 1. 特殊值以原数据类型返回,如:'undefined' 会以 undefined 返回;
* 2. string 数字均会以 number 返回;
* 3. 其余 string 还是以 string 返回;
* 4. 如此一来,返回的交集数组的元素,能不以字符串显示就不以字符串显示;
* 5. 不必纠结 'undefined' 是否字为符串,把它归为 undefined 就好了;
* 6. 同数组的 NaN 或 'NaN' 也能被去重,并且不同数组的 NaN 或 'NaN' 也能纳入交集数组
*/
// 用于匹配特殊值
var r_obj = {
'true': '用',
'false': '于',
'null': '匹',
'undefined': '配',
'NaN': '。'
};
if (item in r_obj) { // 如此,'undefined' 与 undefined 便会被识别为相同值
if (item === true || item === 'true') {
result.push(true);
} else if (item === false || item === 'false') {
result.push(false);
} else if (item === null || item === 'null') {
result.push(null);
} else if (item === undefined || item === 'undefined') {
result.push(undefined);
} else if (item+'' === 'NaN') {
result.push(NaN);
}
} else if (!isNaN(item)) { // 数字都会以 number 显示
result.push(item/1);
} else if (isNaN(item)) { // 其余字符串则不变
result.push(item);
};
};
}
}
}
console.log(hash); // 返回哈希对象,查看各项元素出现的次数
// 输出升序结果数组
return result.sort(function(a, b) {
return a - b;
});
};