判断两个数组是否相似 (arraysSimilar)

Posted by CEC Blog on April 6, 2015

题目

题目来自 慕课网 JavaScript 深入浅出 1-6 编程练习

请在 index.html 文件中,编写 arraysSimilar 函数,实现判断传入的两个数组是否相似。具体需求:

  1. 数组中的成员类型相同,顺序可以不同。例如 [1, true] 与 [false, 2] 是相似的。
  2. 数组的长度一致。
  3. 类型的判断范围,需要区分: String, Boolean, Number, undefined, null, 函数, 日期, window.

当以上全部满足,则返回“判定结果:通过”,否则返回“判定结果:不通过”

题目给出了 index.html 如下:

<!DOCTYPE HTML>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb18030">
    <title>Untitled Document</title>

</head>
<body>
    <script type="text/javascript">   
        /*
         * param1 Array
         * param2 Array
         * return true or false
         */
        function arraysSimilar(arr1, arr2){

        }
    </script>
    <script src="testData.js"></script>
</body>
</html>

其中 testData.js 是测试用例,代码如下

var result = function() {
    //以下为多组测试数据
    var cases = [{
        arr1: [1, true, null],
        arr2: [null, false, 100],
        expect: true
    }, {
        arr1: [
            function() {},
            100
        ],
        arr2: [100, {}],
        expect: false
    }, {
        arr1: [null, 999],
        arr2: [{},
            444
        ],
        expect: false
    }, {
        arr1: [window, 1, true, new Date(), "hahaha", (function() {}), undefined],
        arr2: [undefined, (function() {}), "okokok", new Date(), false, 2, window],
        expect: true
    }, {
        arr1: [new Date()],
        arr2: [{}],
        expect: false
    }, {
        arr1: [window],
        arr2: [{}],
        expect: false
    }, {
        arr1: [undefined, 1],
        arr2: [null, 2],
        expect: false
    }, {
        arr1: [new Object, new Object, new Object],
        arr2: [{}, {},
            null
        ],
        expect: false
    }, {
        arr1: null,
        arr2: null,
        expect: false
    }, {
        arr1: [],
        arr2: undefined,
        expect: false
    }, {
        arr1: "abc",
        arr2: "cba",
        expect: false
    }];

    //使用for循环, 通过arraysSimilar函数验证以上数据是否相似,如相似显示“通过”,否则"不通过",所以大家要完成arraysSimilar函数,具体要求,详见任务要求。    
    for (var i = 0; i < cases.length; i++) {
        if (arraysSimilar(cases[i].arr1, cases[i].arr2) !== cases[i].expect) {
            document.write("不通过!case" + (i + 1) + "不正确!arr1=" + JSON.stringify(cases[i].arr1) + ", arr2=" + JSON.stringify(cases[i].arr2) + " 的判断结果不是" + cases[i].expect);
            return false;
        }
    }
    return true;

}();
document.write("判定结果:" + (result ? "通过" : "不通过"));

解答

各位读者在看解答前也可以自己考虑一下,看看咱们的想法是否一致,期待您在本文的留言。


思路

通过观察测试用例,可以发现,最后三个用例有不是数组的。所以我们可以先判断传入的参数是否是数组。
又因为题目中要求数组长度必须一致,这也是第二个限制条件。
最后再区分具体的类型。

理清思路我们可以分为以下步骤:

  1. 判断传入的参数是否为数组 (使用 instanceof 方法)
  2. 检查两个数组长度是否一致
  3. 分别判断数组内元素的基本数据类型 (使用 typeof 方法)
  4. 因为 typeof 只能检查基本数据类型,对于 null, Date, window 返回的都是 object,所以使用 Object.prototype.toString.apply() 来检查这些对象类型,其返回值为:'[object Null]', '[object Date]', '[object global]'
  5. 分别比较每个数组内元素的各种类型的个数,如果都相等,那么这两个数组是相似的。

具体实现代码

JavaScript代码如下

/**
 * =====================================================
 * 请在index.html文件中,编写arraysSimilar函数,实现判断传入的两个数组是否相似。具体需求:
 * 1. 数组中的成员类型相同,顺序可以不同。例如[1, true] 与 [false, 2]是相似的。
 * 2. 数组的长度一致。
 * 3. 类型的判断范围,需要区分:String, Boolean, Number, undefined, null, 函数,日期, window.
 *
 * 当以上全部满足,则返回"判定结果:通过",否则返回"判定结果:不通过"。
 * =====================================================
 */

/*
* param1 Array
* param2 Array
* return true or false
*/
function arraysSimilar(arr1, arr2){
    if (arr1 instanceof Array && arr2 instanceof Array ) {    //先判断传入的是否是数组
        if (arr1.length == arr2.length) {                    //判断数组长度
            console.log("same-length");
            console.log(arr1);
            console.log(arr2);
            //开始判断数组内部是否相似
            return sameLengthArraysSimilar(arr1, arr2);
        } else{
            //两个数组长度不同返回false
            return false;
        }
    } else {
        //传入的参数不是数组返回false
        return false;
    }
}

/**
 * 判断两个等长的数组内部是否相似
 * 遍历数组
 * arr1中元素各种类型出现的个数是否和arr2中元素各种类型出现的个数相同
 * @param  {Array} arr1 数组1
 * @param  {Array} arr2 数组2
 * @return {true,false}
 */
function sameLengthArraysSimilar(arr1,arr2) {
    var numInArr1 = 0;
    var numInArr2 = 0;
    var booleanInArr1 = 0;
    var booleanInArr2 = 0;
    var funInArr1 = 0;
    var funInArr2 = 0;
    var undefinedInArr1 = 0;
    var undefinedInArr2 = 0;
    var stringInArr1 = 0;
    var stringInArr2 = 0;
    var nullInArr1 = 0;
    var nullInArr2 = 0;
    var dateInArr1 = 0;
    var dateInArr2 = 0;
    var windowInArr1 = 0;
    var windowInArr2 = 0;

    for (var i = 0; i < arr1.length; i++) {
        if(typeof arr1[i] === 'number' ){
            numInArr1 ++;
        } else if(typeof arr1[i] === 'boolean'){
            booleanInArr1 ++;
        } else if(typeof arr1[i] === 'function'){
            funInArr1 ++;
        } else if(typeof arr1[i] === 'undefined'){
            undefinedInArr1 ++;
        } else if(typeof arr1[i] === 'string'){
            stringInArr1 ++;
        } else if(typeof arr1[i] ==='object'){
            if(Object.prototype.toString.apply(arr1[i]) === '[object Null]'){
                nullInArr1 ++;
            } else if(Object.prototype.toString.apply(arr1[i]) === '[object Date]'){
                dateInArr1 ++;
            } else if(Object.prototype.toString.apply(arr1[i]) === '[object global]'){
                windowInArr1 ++;
            }
        }

        if(typeof arr2[i] === 'number'){
            numInArr2 ++;
        } else if(typeof arr2[i] === 'boolean'){
            booleanInArr2 ++;
        } else if(typeof arr2[i] === 'function'){
            funInArr2 ++;
        } else if(typeof arr2[i] === 'undefined'){
            undefinedInArr2 ++;
        } else if(typeof arr2[i] === 'string'){
            stringInArr2 ++;
        } else if(typeof arr2[i] ==='object'){
            if(Object.prototype.toString.apply(arr2[i]) === '[object Null]'){
                nullInArr2 ++;
            } else if(Object.prototype.toString.apply(arr2[i]) === '[object Date]'){
                dateInArr2 ++;
            } else if(Object.prototype.toString.apply(arr2[i]) === '[object global]'){
                windowInArr2 ++;
            }
        }
    }

    console.log("num---"+numInArr1);
    console.log("num---"+numInArr2);
    console.log("boo---"+booleanInArr1);
    console.log("boo---"+booleanInArr2);
    console.log("null---"+nullInArr1);
    console.log("null---"+nullInArr2);
    console.log("window---"+windowInArr1);
    console.log("window---"+windowInArr2);
    console.log("date---"+dateInArr1);
    console.log("date---"+dateInArr2);
    console.log("string---"+stringInArr1);
    console.log("string---"+stringInArr2);
    console.log("fun---"+funInArr1);
    console.log("fun---"+funInArr2);
    console.log("undefined---"+undefinedInArr1);
    console.log("undefined---"+undefinedInArr2);

    if(numInArr1 == numInArr2 && booleanInArr1==booleanInArr2 && funInArr1==funInArr2 && undefinedInArr1==undefinedInArr2 && stringInArr1==stringInArr2 && nullInArr1==nullInArr2 && dateInArr1==dateInArr2 && windowInArr1==windowInArr2){
        console.log('================================true');
        return true;
    }else{
        console.log('================================false');
        return false;
    }
}

总结

  • 上述代码完美的跑完所有的测试用例,读者 点击这里查看结果,并且可以按 f12 看 Console 信息, 里面有代码的执行过程。
  • 当然你也可以复制本文的 JavaScript 代码,在 慕课网的习题 下跑一下,也可以看到 判定结果:通过 的结果
  • 完整源代码在我的 GitHub javascript-test/arraysSimilar/ 仓库中
  • 其实我的代码逻辑并不复杂,有点空间换时间的感觉,执行效率应该是较高的。没有用 JavaScript 封装的任何函数,完全是自己写的。其实代码除去 console.log() 也并没有多少行。
  • 各位读者有什么好的想法欢迎留言交流!