判断数组
在js中怎么判断一个数组,使用instanceof就能轻易解决这个问题,可以参考另一篇博文typeof和instanceof详解
[] instanceof Array // true
instanceof的操作符问题在于,它假定只有一个全局执行环境,如果网页中包含多个框架,也就是存在两个以上不同的全局执行环境,就存在两个以上不同版本的Array构造函数。如果你从一个框架向另一个框架传入一个数组,那么传入的数组与第二个框架中原生创建的数组分别具有不同的构造函数
为了解决这个问题,ECMAScript5新增了Array.isArray()方法
if(Array.isArray(value)){
// 如果value是数组
}
isArray的实现大概是这样的:
function isArray(o) {
// 利用参数的toString方法
return Object.prototype.toString.call(o) === '[object Array]';
}
Array.prototype.isArray = isArray;
具体应用
有这样一个问题,数组A和数组B有序(暂定从小到大),如何判断B是不是数组A的子集
如果忽略有序这个条件,我们很容易想到这样一种实现方式
var arrA,
arrB; //省略初始化
function isSubCollection(arrA, arrB){
var arrC = arrA.concat(); // 用数组C深拷贝数组A,避免破坏arrA
for(var i = 0, len = arrB.length; i < len; i++){
//在数组C中,返回数组B元素的索引
var index = arrC.indexOf(arrB[i]);
if(index >= 0){
//将数组C中与B相同的元素切掉一个
arrC.splice(index, 1);
} else {
return false;
}
}
return true;
}
上面这个方法明显没有用到有序这个条件,导致每次indexOf实际上重复遍历数组A,那么接下来我们使用另一种方法
var arrA,
arrB; //省略初始化
function isSubCollection(arrA, arrB){
var pos = 0;
var isFind = false;
for(var i = 0, len = arrB.length; i < len; i++){
isDiff = false;
//使用循环判断arrB中的元素是否在arrA中,并且用一个pos变量记录在arrA的游标,减少循环次数
for(var j = pos, _len = arrA.length; j< _len; j++){
if(arrA[j] == arrB[i]){
pos = j;
isFind = true;
}
}
if(!isFind) return false;
}
return true;
}
看起来效率高了一些,但实际上没高多少。说到有序,我们自然会想到二分查找,如果两个同时都是大数组,那么使用二分查找来判断数组A中是否有数组B的元素显然更快,时间复杂度为logN
var arrA,
arrB; //省略初始化
function isSubCollection(arrA, arrB){
for(var i = 0, len = arrB.length; i < len; i++){
if(!isFind(arrA, arrB[i])) return false;
}
return true;
}
//使用二分查找
function isFind(arr, target){
var upper = arr.length - 1;
var lower = 0;
while(lower <= upper){
var mid = Math.floor((upper + lower) / 2);
if(arr[mid] == target){
return true;
} else if(arr[mid] < target){
lower = mid + 1;
} else {
upper = mid - 1;
}
}
return false;
}