写在后面

因为这两天测试机房停电,这两天无事可做,闲着干嘛呢?想着要不试着再写篇文章来唠唠吧。于是就有了明天这篇。

题选由来

在上个月,社区里有人提了这么一个问题——这JS判断怎么简化,把我给看晕了

const isDel = (op, o) => {    let fal = false;    if (op.is_show_lock && op.is_show_sf && op.is_show_bz) {        if (o.is_lock && o.is_sf && o.is_bz) {            fal = false;        } else {            fal = true;        }    } else if (op.is_show_lock && op.is_show_sf) {        if (o.is_lock && o.is_sf) {            fal = false;        } else {            fal = true;        }    } else if (op.is_show_lock && op.is_show_bz) {        if (o.is_lock && o.is_bz) {            fal = false;        } else {            fal = true;        }    } else if (op.is_show_sf && op.is_show_bz) {        if (o.is_sf && o.is_bz) {            fal = false;        } else {            fal = true;        }    } else if (op.is_show_lock) {        if (o.is_lock) {            fal = false;        } else {            fal = true;        }    } else if (op.is_show_sf) {        if (o.is_sf) {            fal = false;        } else {            fal = true;        }    } else if (op.is_show_bz) {        if (o.is_bz) {            fal = false;        } else {            fal = true;        }    }    return fal;};

能够看出这段代码次要的逻辑就是依据几个字段来判断出最终的后果输入布尔值。最终笔者给出的解答是——

const isRemove = (op, o) => (op.is_show_lock && !o.is_lock) || (op.is_show_sf && !o.is_sf) || (op.is_show_bz && !o.is_bz)

那么我是如何简化呢?当看到下面一长串的逻辑判断的时候,不言而喻的就是存在太多字段的重复使用,笔者第一感觉就是应该能够用布尔代数来简化,这里就波及到两个知识点了,布尔代数的法令以及布尔代数运算律,对于这两个的理论知识就不做赘述,可点击链接查看或者应用习惯的搜索引擎进行搜寻查阅相干材料。咱们间接进入正题。

简化

首先,咱们再回顾下题主的代码能够看出满足true的条件较少【ps:因为false不仅蕴含了if中的条件,还包含了不满足else的状况,这也是笔者第一次答复有误时的bug之处】,那么就列出所有满足true的布尔表达式如下:

op.is_show_lock && op.is_show_sf && op.is_show_bz && !(o.is_lock && o.is_sf && o.is_bz) || op.is_show_lock && op.is_show_sf && !(o.is_lock && o.is_sf) ||op.is_show_lock && op.is_show_bz && !(o.is_lock && o.is_bz) ||op.is_show_sf && op.is_show_bz && !(o.is_sf && o.is_bz) || op.is_show_lock && !o.is_lock ||op.is_show_sf && !o.is_sf ||op.is_show_bz && !o.is_bz

字段不过是一种示意,所以这里能够用字母来代替,简化表达式假如:

op.is_show_lock -> Aop.is_show_sf -> Bop.is_show_bz -> Co.is_lock -> ao.is_show_lock -> bo.is_show_lock -> c

又因为要示意为数学语言,在数学中:

&& -> ·|| -> +! -> ′

于是,代码用示意为如下布尔代数式:

A · B · C · (a · b · c)′ + A · B · (a · b)′ +A · C · (a · c)′ +B · C · (b · c)′ + A · a′ +B · b′ +C · c′

接下来就是对此布尔代数式套用布尔运算律对其简化得出最终最优的布尔代数。

步骤

  1. 德·摩根律(反演律):(a+b)′=a′·b′,(a·b)′=a′+b′.

    A · B · C · (a′ + b′ + c′) + A · B · (a′ + b′) +A · C · (a′ + c′) +B · C · (b′ + c′) + A · a′ +B · b′ +C · c′
  2. 分配律:a·(b+c)=(a·b)+(a·c),(a+b)·c=(a·c)+(b·c)
    从1步骤的后果看出所有abc均为a′b′c′,那么这里再做一次替换,各自示意为xyz;而后依据分配律可得:

    A · B · C · x + A · B · C · y + A · B · C · z + A · B · x + A · B · y +A · C · x + A · C · z +B · C · y + B · C · z + A · x +B · y +C · z
  3. 交换律:a+b=b+a, a·b=b·a.结合律:(a+b)+c=a+(b+c) ,(a·b)·c=a·(b·c).
    从第2步骤中能够看出存在两两子项有公共代数式,如:A · B · x,A · x;依据交换律和结合律,可对其组合运算,这里暂以这两个为例:
    A · B · x + A · x
  4. 零一律(幺元律):a+0=a, a·1=a.
    A · B · x + A · x · 1
  5. 分配律:a·(b+c)=(a·b)+(a·c),(a+b)·c=(a·c)+(b·c)
    A · x · (B + 1)
  6. 囿元律(极元律):a+1=1, a·0=0.
    A · x
  7. 依据3~6步骤的运算,得出了A · B · x + A · x = A · x ,反复以上步骤对其余两两子代数运算最终得出代数式:

    A · x +B · y +C · z

    至此,布尔代数式已不可再优化,那么就能够将其依照起初约定的转为如下代码:

    (op.is_show_lock && !o.is_lock) || (op.is_show_sf && !o.is_sf) || (op.is_show_bz && !o.is_bz)

    写在最初

    在我作为开发的5年工夫里,尚未碰到题主的状况,呈现这种代码的状况概率应该也比拟少,即便碰到,大多数人可能也会用答复中的其余计划,但大多逃离不了循环,复杂度间接从O(1)变为O(N),尽管最终的影响微不足道,但理解下其余更优的计划也是百利有害的,从可读性上来说也有晋升,读者若是遇到此类代码能够尝试用下这个技巧。