美文网首页
一个if else的优化小思考题

一个if else的优化小思考题

作者: wudimingwo | 来源:发表于2019-03-08 14:07 被阅读0次

题目
有一组未知数量与值的数字,要求把他们分成三份, 使每份的和尽量相等.

思路

  1. 对数组进行降序排序
  2. 创建三个数组,记录每个数组的当前之和
  3. 下个数分配给当前之和最小的数组.

版本1.0

      var arr = [5, 2, 6, 88, 6, 95, 15, 45, 22];
      // 进行排序 
      arr = arr.sort(function(a, b) {
        return b - a
      });
      // 分为三组,记录当前之和
      var oneArr = [],
        twoArr = [],
        threeArr = [];
// 记录当前之和的
      oneArr.sum = 0;
      twoArr.sum = 0;
      threeArr.sum = 0;
      for(var i = 0; i < arr.length; i++) {
        if(oneArr.sum <= twoArr.sum) {
          if(oneArr.sum <= threeArr.sum) {
            oneArr.sum += arr[i];
            oneArr.push(arr[i]);
          } else {
            threeArr.sum += arr[i];
            threeArr.push(arr[i]);
          }
        } else {
          if(twoArr.sum <= threeArr.sum) {
            twoArr.sum += arr[i];
            twoArr.push(arr[i]);
          } else {
            threeArr.sum += arr[i];
            threeArr.push(arr[i]);
          }
        }

      }
      console.log('oneArr',oneArr,'twoArr',twoArr,'threeArr',threeArr);

觉得很难看,
一个是一堆if else 很难看, 另一个是 这个名字和数据结构很难看
能不能优化一下?

版本2.0 switch + Math.min

      var arr = [5, 2, 6, 88, 6, 95, 15, 45, 22];
      arr = arr.sort(function(a, b) {
        return b - a
      });
      var oneArr = [],
        twoArr = [],
        threeArr = [],
        a = 0,
        b = 0,
        c = 0,
        item;
      for(var i = 0; i < arr.length; i++) {
        item = arr[i];
        switch (Math.min(Math.min(a,b),c)){
            case a:
              a += item;
              oneArr.push(item);
                break;
            case b:
            b += item;
            twoArr.push(item);
                break;
            case c:
            c += item;
            threeArr.push(item);
                break;
        }
      }
      console.log('oneArr',a,oneArr,'twoArr',b,twoArr,'threeArr',c,threeArr);

其实如果不是思路层面的变化,
那么优化的关键就是如何存储数据的问题,
如何设立数据, 如何获取数据, 如何让数据之间进行联系标记的问题.
而我们想要的效果是分支比较少, 又或者层级比较浅.

明显 oneArr 和 a, twoArr 和 b, threeArr 和 c 之间是有联系的.
这种联系在版本1.0中是直接用对象属性的方式进行了标记, 但没能直接用上.
在版本2.0中是在 switch 里进行联系, 实际上不算从数据层面上进行了紧密相连.

怎样让 oneArr 和 a 两个之间进行联系的问题, 需要通过a 找到 oneArr

在对象这种数据结构中, 确实存在if else
比如 father.son => 123, 实际上 father + ['son'] 就可以找到 123 这个值.
在这里 father 可以看做是一种空间(变量),
'son' 可以看做是一个条件, 或者是一个条件的结果.

想不出来..对象版本...

思考一个问题
我想让oneArr 和 a 两个变量之间, 能够互相找到对方,
即,我找到oneArr时,就能找到a, 找到a时就能找到oneArr,
怎么做?

第一种思路, 两者之间在概念上的关系, 即算法上的关系.
在这道题中, a 其实是 oneArr的各项之和.
所以通过oneArr是可以计算出a 的,
但反过来, 通过a 是无法逆算出 oneArr这个数组的.

第二种思路, 我们可以通过诸如对象这种数据形式, 让他们俩产生联系.

// 由于 oneArr 和 a 都是引用值, 所以这是可能的
      var oneArr = [1,2,3];
      var a = {};
      oneArr.a = a;
      a.oneArr = oneArr;

// 则真正用来存和的a 实际上就要变成 sum;
      a.sum = oneArr.reduce(function (a,b) {
        return a += b
      });

但似乎很少这样做, 因为从某种角度来讲,这是种死循环.
或者比较容易形成死循环.

更常见的对象结构应该是这样 (也就是版本1.0的样子)

     var obj = {};
     obj.arr = [1,2,3];
     obj.sum = oneArr.reduce(function (a,b) {
        return a += b
      });

我之前通常想到的就是用这种结构去产生联系,
可严格来讲, arr 并不能找到sum , sum 也并不能找到 arr,
obj能够找到他们俩, 如果sum,和arr 能够找到obj , 实际上就能找到彼此.
但在这门语言里是不存在, 子找父的. 继承关系中, 能够找到prototype,
但在一般对象关系中则不存在.

又或者好像还有类似这种,通过字符串产生间接联系的

var a = 'some';
var arr[a] = [1,2,3];
var sum[a] = 6;

arr 和 sum 没有任何直接关系, 不过他们拥有同一个属性 'some',
即, 通过'some' 这个字符串, 就可以到各自的空间中, 取出对应的数据.

-------------------------------------------------
把例题改一下, 就会出现, 下面这种看起来很恶心的东西出来.


      var objArr = {};
      var objSum = {};
      var keyArr = ['one','two','thr'];
      for(var i = 0; i < keyArr.length; i++) { // 初始化
        objArr[keyArr[i]] = [];
        objSum[keyArr[i]] = 0;
      }        
      for(var i = 0; i < arr.length; i++) {
        item = arr[i];
        switch (Math.min(Math.min(objSum[keyArr[0]],objSum[keyArr[1]]),objSum[keyArr[2]])){
            case objSum[keyArr[0]]:
              objSum[keyArr[0]] += item;
              objArr[keyArr[0]].push(item);
                break;
            case objSum[keyArr[1]]:
            objSum[keyArr[1]] += item;
            objArr[keyArr[1]].push(item);
                break;
            case objSum[keyArr[2]]:
            objSum[keyArr[2]] += item;
            objArr[keyArr[2]].push(item);
                break;
        }
      }

es6中出现了一个map的东西, 从这篇文章的角度来讲,
map比对象的优点在于, 对象的属性必须只能是个字符串,
比如

 obj['some'] = 123;
obj.mike 实际上就等同于 obj['mike']
对于obj 这个对象而言, 后面中括号中基本都是字符串,
即使不是字符串, 内部也会使用 toString 进行转化.

比如

obj[{}] = 111; / 存值
obj[{}] / 返回 111
obj[{a:1}] / 返回111
obj['[object Object]'] / 返回的也是111, 所有对象都会返回111
因为在存取时, 对象会调用 toString 方法, 
而所有对象的 toString 方法返回的都是'[object Object]',

比如
obj[[]] = 222; / 存值
obj[''] / 返回 222
因为 [] 调用 toString 会返回 ''
Array的原型链上的toString 方法似乎会调用 join方法.

比如
obj[1] = 333; / 此时的1 的数据类型是 Number
obj[1] / 返回333 很正常
obj['1'] / 返回333 表明他存进去之前, 1 也经历了 toString 的过程.

总之, 对象后面的值必须是字符串类型.
而map 就不同了, 他可以识别各种类型,
并且能够识别引用值的地址.

      var m = new Map();
      /存值
      var a = 1;
      var b = '1';
      m.set(a,'aaa');
      m.set(b,'bbb');
      /取值
      m.get(a) ; / 返回'aaa'
      m.get(b) : / 返回'bbb'
      m.get(1) ; / 返回'aaa'
      m.get('1') : / 返回'bbb'
      表明能够识别类型, 起码不会发生内部toString转化的现象.

      然后是引用值的问题
      
      var a = [];
      var b = {};
      / 存值
      m.set(a,'ccc');
      m.set(b,'ddd');
      / 取值
      m.get(a) / 返回'ccc'
      m.get(b) / 返回'ddd'
      / 问题来了
      m.get([]) / 返回undefined
      m.get({}) / 返回 undefined
      其实不难理解, 因为引用值实际上存的是地址,
      我接连写三个 空数组 [],[],[]
      这三个数组看似相同, 实际上每个的地址都不同.
      
      所以像下面这样是没有用的
      m.set([1,2],'quick');
      m.get([1,2]) / 返回的不是quick 而是 undefined

      所以当你想用map 并用引用值来充当key的时候,
      一般就是要用一个变量来接收这个地址.否则,你是找不到这个地址的.

      但是返回来却是这样的, 只要一个引用值的地址不变,
      而引用值"内部"的值变化是不会产生影响的.

      比如
      var obj = {age : 18};
      m.set(obj,'mike');
      m.get(obj); / 返回mike , 没毛病.
      更改一下 obj
      obj.age = 19; / 注意, obj本身的地址是没有更新的, 除非用等号重新赋值.
      m.get(obj); / 返回 mike, 也没毛病.
      

回过头我们用map硬套一下这道题


相关文章

  • 一个if else的优化小思考题

    题目有一组未知数量与值的数字,要求把他们分成三份, 使每份的和尽量相等. 思路 对数组进行降序排序 创建三个数组,...

  • 代码存在大量的if/else优化方案总结

    过多的else if 会使代码臃肿而简陋,下面是优化方案总结 一、多个else if分支优化 1.Key-valu...

  • if/else优化

    优化 if/else 语句 当逻辑或||时,找到为 true 的分项就停止处理,并返回该分项的值,否则执行完,并返...

  • 优化if else

    引用地址:https://www.jianshu.com/p/4c035c271a10

  • 优化 if/else

    代码中经常有一些 if/else 连环判断,如果是入参判断,我们可以使用 Hibernate-Validator ...

  • 鹅厂实习| 周记(四)

    以下是本周的知识清单: TypedArray if-else优化 注解替代枚举 一点小感悟 1.TypedArra...

  • 优化 if - else代码

    在javascript流程控制中并没有像java中有goto跳转,所以基本上都是用if...if 或者if...e...

  • 优化if-else

    简介: 从一开始学编程的时候,就开始接触到if-else,也是最简单的一个条件分支,包括到现在,依然很重要,在代码...

  • 如何优化if else if

    最近在优化以前的旧代码,发现代码中有大量的if else if的代码块 主要存在以下问题: 问题1: if els...

  • 黑马头条第9天_18关注作者代码优化

    课程 if else 嵌套太复杂优化,清爽开发代码如下:

网友评论

      本文标题:一个if else的优化小思考题

      本文链接:https://www.haomeiwen.com/subject/krkrpqtx.html