• 对“心理学测测你的本命专业”的实现与算法分析


    1 研究对象

    对象名称:心理学测测你的本命专业
    对象链接:https://cdn-act.knowyourself.cc/life_profession/

    2 简单测试

    (1) 多次测试,每次测试选择固定的答案,发现结果始终相同。

    3 Network分析

    (1) 使用Microsoft Edge浏览器开发者工具下的“网络”(chrome开发者工具中叫做Network)分析数据包。

    (2) 对答题过程进行抓包分析如下图,发现在答题过程中和“查看结果”都只进行了图片获取的请求。

    (3) 根据以上发现和分析数据没有被发送到服务器,故业务逻辑是放在本地被执行的。

    3 业务逻辑分析

    (1) 在开发者工具下的控制台(chrome开发者工具中叫做Console)中发现打印了如下图信息,打印的信息包含答题记录和获取的专业名称的拼音。如土木工程学==tumugongcheng

    (2) 上图中打印的答题记录长度是11,其中包括选择的性别和十道题目。同时可以看到打印这些信息的文件是“index.tsx”,并且发现有两个index.tsx文件。

    (3) 对两个index.tsx分析
    ① 打印“答题记录”的index.tsx文件,如下图中红色框中是核心代码。核心代码实现的功能是:对输入信息规范化和提示,跳转到下一页。

    ② 打印“专业名拼音”的index.tsx文件,如下图,其核心功能是:获取答题记录通过result函数转换为整数,在通过这个整数在数组done_string_2中获取对应的专业。

    数组done_string_2如下。

    const done_string_2 = ["jingjixue", "zhexue", "faxue", "shehuixue", "jiaoyuxue", "hanyuyan", "waiguo", "xinwenxue", "lishixue", "shuxue", "wulixue", "huaxue", "shengmingkexue", "dilixue", "xinlixue", "jisuanjikexue", "tumugongcheng", "jianzhuxue", "jidiangongcheng", "nonglinxue", "yixue", "guanlixue", "yishu", "xijuyingshi", "biaoyan", "tiyuxue", "kaoguxue", "dianzijingji"]
    

    数组done_string_2和函数result函数在代码中的位置如下图。

    4 算法详解

    (1) 根据上述分析,“心理学测测你的本命专业”的工作流程是,先获取用户答题记录,再将答题记录转换整数index,最后从数组done_string_2中获取索引为index的值。
    (2) 代码中传递给函数result的实参是select.slice(1),使用单步调试获取变量select的内容
    ① 变量ctx获取用户的信息,如:姓名(name: han),专业(profession: 电子信息),答题记录(select_q_list)如下图。

    select_q_list的内容如下图。

    ② 变量select的内容如下图,变量select对变量select_q_list进行了数据格式转换。

    (3) 核心算法
    算法位于result.js文件中。
    (1) 算法中,变量config把每个问题的答案映射为一个数组,数组中每一个数字对应一个专业。变量config如下

      var config = {
        0: {
          0: [1, 0, 2, 3, 4, 5, 6, 7, 8, 21, 26],
          1: [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 26],
          2: [22, 23, 24, 25, 27],
        },
        1: {
          0: [0, 2, 6, 7, 20, 21, 25],
          1: [3, 4, 24],
          2: [5, 14, 22],
          3: [1, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 23, 26, 27],
        },
        2: {
          0: [1, 3, 4, 5, 9, 10, 14, 21, 22, 23, 24, 27],
          1: [0, 2, 6, 7, 8, 11, 12, 13, 15, 16, 17, 18, 19, 20, 25, 26],
        },
        3: {
          0: [0, 2, 3, 4, 6, 7, 20, 21, 24, 25],
          1: [1, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 26, 27],
        },
        4: {
          0: [1, 3, 4, 5, 9, 10, 14, 21, 22, 23, 24, 27],
          1: [0, 2, 6, 7, 8, 11, 12, 13, 15, 16, 17, 18, 19, 20, 25, 26],
        },
        5: {
          0: [1, 0, 2, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 23, 25, 26, 27],
          1: [3, 4, 5, 14, 22, 24],
        },
        6: {
          0: [1, 8, 9, 10, 11, 12, 13, 20, 26],
          1: [5, 22, 23, 24],
          2: [15, 16, 17, 18, 19, 25, 27],
          3: [3, 4, 6, 7, 14],
          4: [0, 2, 21],
        },
        7: {
          0: [1, 8, 9, 10, 11, 12, 13, 20, 26],
          1: [5, 22, 23, 24],
          2: [15, 16, 17, 18, 19, 25, 27],
          3: [3, 4, 6, 7, 14],
          4: [0, 2, 21],
        },
        8: {
          0: [4, 5, 7, 14, 21, 23, 6],
          1: [6, 15],
          2: [13],
          3: [10, 16, 17, 18],
          4: [12, 19, 20, 25],
          5: [1, 2, 7, 21],
          6: [0, 9, 15, 16, 18, 10, 14],
          7: [17, 22, 24, 23],
          8: [3, 8, 26, 13],
          9: [11, 12, 19, 20, 26],
          10: [25, 27],
          11: [22, 24],
        },
        9: {
          0: [],
          1: [],
          2: []
        }
      };
    

    (2) 统计所有问题映射的数组,并把这些数组合并成一个数组存储在变量result中

      var result = [];
      for (var topic_num = 0; topic_num < select.length; topic_num++) {
        // 遍历本题答案
        for (var j = 0; j < select[topic_num].length; j++) {
          var user_select = select[topic_num][j];
          // 获取配置
          var tmp = config[topic_num][user_select];
          // 合并
          result = result.concat(tmp);
        }
      }
    

    (3) 统计变量result中出现最多次的数字,并返回该数字

      var result_map = {};
      var max = -1;
      // 打乱一下result结果
      result.shuffle();
      for (var i = 0; i < result.length; i++) {
        if (typeof result_map[result[i]] == "undefined") {
          result_map[result[i]] = 0;
        }
        result_map[result[i]]++;
        if (max == -1) {
          max = result[i];
        } else {
          if (result_map[result[i]] > result_map[max]) {
            max = result[i];
          }
        }
      }
    
      //console.log(result);
      //console.log(result_map);
      //console.log(max);
      return max;
    

    5 附录result.js完整代码

    // 结果页id:
    // 0:经济学
    // 1:哲学
    // 2:法学
    // 3:社会学
    // 4:教育学
    // 5:汉语言文学
    // 6:外国语言学
    // 7:新闻学
    // 8:历史学
    // 9:数学
    // 10:物理学
    // 11:化学
    // 12:生命科学
    // 13:地理学
    // 14:心理学
    // 15:计算机科学与技术
    // 16:土木工程学
    // 17:建筑学
    // 18:机电工程学
    // 19:农林学
    // 20:医学
    // 21:管理学
    // 22:艺术
    // 23:戏剧影视导演
    // 24:表演艺术
    // 25:体育学
    // 26:考古学
    // 27:电子竞技
    
    //10道题,选择传入数组,因为有多选,数组内套数组
    //选择顺序从0开始算,0代表第一个选项,1代表第二个...
    //例如 select :[[0],[1],[3],[0],[0,1,2,3],[0,1,2,3,4],[0]]
    function getResult(select) {
      if (!Array.prototype.shuffle) {
        Array.prototype.shuffle = function () {
          for (var j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x)
            return this;
        };
      }
      var config = {
        0: {
          0: [1, 0, 2, 3, 4, 5, 6, 7, 8, 21, 26],
          1: [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 26],
          2: [22, 23, 24, 25, 27],
        },
        1: {
          0: [0, 2, 6, 7, 20, 21, 25],
          1: [3, 4, 24],
          2: [5, 14, 22],
          3: [1, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 23, 26, 27],
        },
        2: {
          0: [1, 3, 4, 5, 9, 10, 14, 21, 22, 23, 24, 27],
          1: [0, 2, 6, 7, 8, 11, 12, 13, 15, 16, 17, 18, 19, 20, 25, 26],
        },
        3: {
          0: [0, 2, 3, 4, 6, 7, 20, 21, 24, 25],
          1: [1, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 26, 27],
        },
        4: {
          0: [1, 3, 4, 5, 9, 10, 14, 21, 22, 23, 24, 27],
          1: [0, 2, 6, 7, 8, 11, 12, 13, 15, 16, 17, 18, 19, 20, 25, 26],
        },
        5: {
          0: [1, 0, 2, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 23, 25, 26, 27],
          1: [3, 4, 5, 14, 22, 24],
        },
        6: {
          0: [1, 8, 9, 10, 11, 12, 13, 20, 26],
          1: [5, 22, 23, 24],
          2: [15, 16, 17, 18, 19, 25, 27],
          3: [3, 4, 6, 7, 14],
          4: [0, 2, 21],
        },
        7: {
          0: [1, 8, 9, 10, 11, 12, 13, 20, 26],
          1: [5, 22, 23, 24],
          2: [15, 16, 17, 18, 19, 25, 27],
          3: [3, 4, 6, 7, 14],
          4: [0, 2, 21],
        },
        8: {
          0: [4, 5, 7, 14, 21, 23, 6],
          1: [6, 15],
          2: [13],
          3: [10, 16, 17, 18],
          4: [12, 19, 20, 25],
          5: [1, 2, 7, 21],
          6: [0, 9, 15, 16, 18, 10, 14],
          7: [17, 22, 24, 23],
          8: [3, 8, 26, 13],
          9: [11, 12, 19, 20, 26],
          10: [25, 27],
          11: [22, 24],
        },
        9: {
          0: [],
          1: [],
          2: []
        }
      };
    
      var result = [];
      for (var topic_num = 0; topic_num < select.length; topic_num++) {
        // 遍历本题答案
        for (var j = 0; j < select[topic_num].length; j++) {
          var user_select = select[topic_num][j];
          // 获取配置
          var tmp = config[topic_num][user_select];
          // 合并
          result = result.concat(tmp);
        }
      }
      var result_map = {};
      var max = -1;
      // 打乱一下result结果
      result.shuffle();
      for (var i = 0; i < result.length; i++) {
        if (typeof result_map[result[i]] == "undefined") {
          result_map[result[i]] = 0;
        }
        result_map[result[i]]++;
        if (max == -1) {
          max = result[i];
        } else {
          if (result_map[result[i]] > result_map[max]) {
            max = result[i];
          }
        }
      }
    
      //console.log(result);
      //console.log(result_map);
      //console.log(max);
      return max;
    }
    
    // test
    // console.log(getResult([[0], [3], [0], [1], [0], [0], [0], [0], [0, 5, 6], [1]]));//期望结果 1
    //getResult([[1],[3],[1],[1],[1],[0],[2],[2],[1,2,6],[1]]);//期望结果 15
    //getResult([[2],[3],[0],[1],[0],[0],[1],[1],[0,7,10],[1]]);//期望结果 23
    
    export default getResult;
    

    6 结束语

    把每个专业映射为数字,再把每个问题的答案映射为一组数字,最后统计出现次数最多的数字就是专业。
    不得不说这种映射和众数的思想真是完美。大佬!就是牛!

    思考题。为什么在变量config中对第十个问题答案的映射全是空?
    第十个问题如下图

    变量config中对第十个问题答案的映射

      9: {
          0: [],
          1: [],
          2: []
        }
    
  • 相关阅读:
    flex 自定义事件
    ssis 不停执行的方法
    动态修改大小的Panel用户控件
    ssis 写文件到数据库
    sqlserver CheckSum
    poj1423
    poj1860
    poj1862
    poj1426
    poj1234
  • 原文地址:https://www.cnblogs.com/HanYG/p/14824633.html
Copyright © 2020-2023  润新知