表驱动法 -优化逻辑分支

表驱动法 -优化逻辑分支

定义

表驱动法(Table-Driven Approach)是一种编程模式,可以将输入变量作为直接或间接索引在表里查找所需的结果或处理函数,而不使用逻辑语句(if-else 和 switch-case)。索引表可以是一个数组、map、或者其它数据结构。

事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和直白,但随着逻辑链的越来越复杂,查表法也就愈发显得更具有吸引力。

使用总则

适当的情况下,采用表驱动法,所生成的代码会比复杂的逻辑代码更简单,更容易修改,而且效率更高。

应用

查询方式

可以分为:直接访问、索引访问、阶梯访问三种

直接访问

举例:查询今天是星期几?

常规写法:

const day = new Date().getDay()
let day_zh;
if(day === 0){
    day_zh = '星期日'
}else if(day === 1) {
    day_zh = '星期一'
}
...
else{
    day_zh = '星期六'
}

// 或者 用 switch case
switch(day) {
    case 0:
        day_zh = '星期日'
        break;
    case 1:
        day_zh = '星期一'
        break;
        ...
}

优化写法:将数据存到查询表里

const week = ['星期日', '星期一',..., '星期六']
const day = new Date().getDay(
const day_zh = week[day]

举例2:保险费率的查询,费率会根据年龄、性别、婚姻状态等不同情况变化

常规写法:使用逻辑分支(if 或 switch) 会非常麻烦

if (gender === 'female') {
    if (hasMarried) {
        if (age < 18) {
            //
        } else {
            // 
        }
    } else if (age < 18) {
        //
    } else {
        // 
    }
} else {
    ...
}

优化写法:结构清晰,容易维护

enum ages {
    unAdult = 0,
    adult = 1
}
enum genders {
    female = 0,
    male = 1
}
enum marry = {
    unmarried = 0,
    married = 1
}

const age2key = (age: number): string => {
    if (age < 18) {
        return ages.unAdult
    }
    return ages.adult
}

// 查询表
const rates: number[] = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]

// 通过检查条件,获取索引值
const premiumRate = {
    0: [age.unAdult, genders.female, marry.unmarried],
    1: [age.unAdult, genders.female, marry.married],
    2: [age.unAdult, genders.male, marry.unmarried],
    3: [age.unAdult, genders.male, marry.unmarried],
    4: [age.adult, genders.female, marry.unmarried],
    5: [age.adult, genders.female, marry.married],
    6: [age.adult, genders.male, marry.unmarried],
    7: [age.adult, genders.male, marry.unmarried]
}
type BoolCode = 0 | 1
const getRate = (age: number, hasMarried: BoolCode, gender: BoolCode) => {
    const ageKey: BoolCode = age2key(age)
    let index: string = ''
    Object.keys(premiumRate).forEach((key, i) => {
        const condition: BoolCode[] = premiumRate[key]
        if (condition[0] === ageKey 
            && condition[1] === gender
            && condition[2] === hasMarried
        ) {
            index = key;
        }
    })
    return rates[index];
}
索引访问

在处理类似年龄范围的时候,无法通过简单的数学运算得到key,可以通过构建索引表、查询表来解决。
在这里插入图片描述

举例:

保险费率根据不同年龄费率不同,不满18岁费率0.2,18-65岁费率0.4,65岁及以上费率0.6。

假设人刚出生是0岁,最多能活到100岁,需要创建一个长度为101的数组,数组的下标对应着人的年龄,这样在0-17的每个年龄储存’<18’,在18-65储存’18-65’, 在65以上储存’>65’。

通过年龄就可以拿到对应的索引,再通过索引来查询对应的数据。

看起来这种方法要比上面的直接访问表更复杂,但是在一些很难通过转换键值、数据占用空间很大的场景下可以试试通过索引来访问。

const ages: string[] = ['<18', '<18', '<18', '<18', ... , '18-65', '18-65', '18-65', '18-65', ... , '>65', '>65', '>65', '>65']
const ageKey: string = ages[age];

索引访问优点

  1. 节省空间,比直接索引的全表法节约空间

  2. 灵活, 根据不同的字段生成不同的索引表

  3. 可维护性强

阶梯访问

不如索引结构直接,但是要比索引访问方法节省空间。

阶梯结构的基本思想:表中的记录对于不同数据范围有效,而不是对不同的数据点有效。
在这里插入图片描述

举例:考试按照分数进行等级评定

优 >= 90

良 < 90

中 < 80

差 < 60

常规写法

let level = '优'
if(score <60 ){
	level = '差'
}else if(score < 80) {
	level = '中'
}else if(score < 90) {
    level = '良'
}

优化写法

const levelTable = ['差', '中', '良', '优']
const scoreCeilTable = [60, 80, 90, 100]

function getLevel(score) {
  const len = scoreCeilTable.length
  for(let i = 0; i < len; i++) {
    const scoreCeil = scoreCeilTable[i]
    if(score <= scoreCeil) {
      return levelTable[i]
    }

  }
  return levelTable[len - 1]
}

注意事项:

  1. 留心边界端点

    注意边界:< 与 <=,确认循环能够在找出最高一级区间后恰当地终止。

  2. 二分查找替代顺序查找

    上面例子用了顺序查找,当数据比较大时,查找成本还是比较大的,应该考虑用二分查

  3. 考虑用索引访问来取代阶梯技术

    阶梯查找比较耗时,如果速度非常重要,可以用索引访问来取代阶梯,用空间换时间,但也要分情况,因为离散空间是不能够完全替代连续空间的

存储类型

查询表从存储上可以分为数据表、逻辑表。

  • 数据表:仅存储结果数据

  • 逻辑表:逻辑处理的代码或者引用

逻辑表

举例:

常规写法:

if (key = "Key A")
{
   执行 Key A 相关的行为。
}
else if (key = "Key B")
{
   执行 Key B 相关的行为。
}

优化写法

let table = {
  A: {
    data: "数据1",
    action () {
      console.log('action 1')
    }
  },
  B: {
    data: "数据2",
    action () {
      console.log('action 2')
    }
  }
}

function handleTable(key) {
  return table[key]
}

console.log(handleTable('A').data)
handleTable('A').action()

总结

表驱动的意义是将数据和逻辑剥离,在开发中,直接修改配置比修改逻辑要更加安全。数据的添加、删除比逻辑条件的添加、删除风险更低,数据来源也更加灵活。

在大多数情况下,优先使用直接访问和索引访问,除非两者实在无法处理,才考虑使用阶梯访问。

使用表的关键在于如何构建查询表内容,如何从表中查询,如何选择合适的查询表。

参考资料

一文道尽“表驱动法”

使用表驱动写出更优雅的条件判断

十分钟魔法练习:表驱动编程

使用表驱动法替代普通的判断分支语句(JS的深入探索)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/736592.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安卓中使用ttf字体文件

官方文档中提供的方法要设备能访问google&#xff1f; 官方方法 直接下载字体的fft文件 我要使用的是lexend 需要的格式可以在里面搜索 使用下载的ttf文件 解压出来 可以单独使用static里面的&#xff0c;里面是直接的lexend的各种格式 但是我这里直接使用Lexend-Vari…

连接Huggingface报requests.exceptions.SSLError错误

最近在学习使用 SHAP 算法解释 BERT 模型的输出结果&#xff0c;然而在从 Huggingface 上导入模型和数据集的过程中出现了网络连接相关的错误&#xff0c;本文用于记录错误类型和解决错误的方法。 1 代码示例 SHAP 官方展示的代码如下&#xff1a; import datasets import nu…

Linux应急响应——知攻善防应急靶场-Linux(1)

文章目录 查看history历史指令查看开机自启动项异常连接和端口异常进程定时任务异常服务日志分析账户排查总结 靶场出处是知攻善防 Linux应急响应靶机 1 前景需要&#xff1a; 小王急匆匆地找到小张&#xff0c;小王说"李哥&#xff0c;我dev服务器被黑了",快救救我&…

视频格式怎么转换?9 个免费视频转换工具

前 9 款免费视频转换器有哪些&#xff1f;在此视频转换器评论中&#xff0c;我们收集了一些有用的提示并列出了顶级免费视频转换器软件&#xff0c;还找出了适合所有级别&#xff08;从初学者到专家&#xff09;的最佳免费视频转换器。 1. Geekersoft免费在线视频转换 最好的免…

【报错】JDBC SQL语句表名报错 解决办法

解决办法 修改检测等级 不是检测有问题吗&#xff0c;那就将idea的检测问题取消掉或者修改检测问题等级&#xff0c;根本问题上我们写的sql语句是一个字符串传过去&#xff0c;只要在mysql查询语句能够正确执行&#xff0c;不要这种检测也罢。

实际项目开发:Spring集成Redis,并实现短信登录功能

redis新手&#xff0c;学了几种基本数据类型&#xff0c;却不知道怎么使用&#xff1f; 总是一边学一边忘&#xff1f; 学会了Redis的大多数使用命令&#xff0c;却不知道如何在项目中使用&#xff1f; 本文将从实际出发&#xff0c;为大家解决这些问题。 我是蚊子码农&#xf…

TikTok账号运营:静态住宅IP为什么可以防封?

静态住宅IP代理服务是一种提供稳定、静态IP地址并可隐藏用户真实IP地址的网络代理服务。此类代理服务通常使用高速光纤网络来提供稳定、高速的互联网体验。与动态IP代理相比&#xff0c;静态住宅IP代理的IP地址更稳定&#xff0c;被封的可能性更小&#xff0c;因此更受用户欢迎…

JAVA学习过程中遇到的问题

前言 记录学习过程中遇见的各种问题。希望对你有帮助。 目录 前言 1、新建maven项目时&#xff0c;archetype项目骨架加载慢 2、maven的pop.xml添加依赖项无法检测到 3、java: 无效的目标发行版: 20 4、idea添加maven依赖太慢 5、CTRLCV复制粘贴太慢 6、Swagger写接口文…

20240621日志:大模型压缩-从闭源大模型蒸馏

目录 1. 核心内容2. 方法2.1 先验估计2.2 后验估计2.3 目标函数 3. 交叉熵损失函数与Kullback-Leibler&#xff08;KL&#xff09;损失函数 location&#xff1a;beijing 涉及知识&#xff1a;大模型压缩、知识蒸馏 Fig. 1 大模型压缩-知识蒸馏 1. 核心内容 本文提出在一个贝…

(Amazing!) 通过 vfox 在 Windows 上安装管理多个 Erlang/OTP 和 Elixir 的版本

大概一个多月前, 我写了篇关于如何使用跨平台版本管理工具 vfox 在 Linux 系统下安装管理多个 Erlang/OTP 版本的文章 -> 通过 vfox 安装管理多版本 Erlang 和 Elixir. 文章使用的示范操作系统是 Ubuntu 20.04 Linux 操作系统. 最近 vfox-erlang 和 vfox-elixir 插件的最新…

如何关闭软件开机自启,提升电脑开机速度?

如何关闭软件开机自启&#xff0c;提升电脑开机速度&#xff1f;大家知道&#xff0c;很多软件在安装时默认都会设置为开机自动启动。但是&#xff0c;有很多软件在我们开机之后并不是马上需要用到的&#xff0c;开机启动的软件过多会导致电脑开机变慢。那么&#xff0c;如何关…

xshell使用vi命令:bash:vim:command not found

你们好&#xff0c;我是金金金。 场景 此时我通过xshell客户端连接到了远程的虚拟机。想用vi命令编辑一个文件时&#xff0c;显示&#xff1a;bash: vim: command not found 排查 看报错提示就可以知道&#xff0c;没找到vim命令 解决 使用包管理器 apt 来安装 vim 更新你的软…

springboot+vue+mybatis旅游管理+PPT+论文+讲解+售后

随着人民生活水平的提高,旅游业已经越来越大众化,而旅游业的核心是信息,不论是对旅游管理部门、对旅游企业,或是对旅游者而言,有效的获取旅游信息,都显得特别重要.旅游管理系统将使旅游相关信息管理工作规范化、信息化、程序化,提供旅游景点、旅游线路,旅游新闻等服务本文以jsp…

ubuntu18.0.4安装gradio踩坑记

Collecting pandas (from gradio) Downloading http://mirrors.cloud.aliyuncs.com/pypi/packages/c3/e2/00cacecafbab071c787019f00ad84ca3185952f6bb9bca9550ed83870d4d/pandas-1.1.5-cp36-cp36m-manylinux1_x86_64.whl (9.5MB) 100% |████████████████…

Python学习打卡:day14

day14 笔记来源于&#xff1a;黑马程序员python教程&#xff0c;8天python从入门到精通&#xff0c;学python看这套就够了 目录 day14102、封装三大特性对用户隐藏的属性和行为私有成员使用私有成员 103、封装的课后习题104、继承单继承多继承 105、复写父类成员和调用父类成…

神经网络学习3-卷积层

膨胀卷积&#xff0c;也被称为空洞卷积或扩张卷积&#xff0c;是一种特殊的卷积运算&#xff0c;它在标准卷积的基础上引入了一个额外的超参数&#xff0c;即膨胀率&#xff08;dilation rate&#xff09;。这个超参数决定了在卷积核的元素之间插入多少额外的空间。通过这种方式…

图解注意力

图解注意力 Part #2: The Illustrated Self-Attention 在文章前面的部分&#xff0c;我们展示了这张图片来展示自注意力被应用于正在处理单词"it"的一层中&#xff1a; 在本节中&#xff0c;我们将看看这是如何完成的。请注意&#xff0c;我们将以一种试图理解单…

Linux系统编程--软/硬连接

真正找到磁盘上文件的并不是文件名&#xff0c;而是inode。 其实在linux中可以让多个文件名对应于同一个inode。 命令&#xff1a; 软连接&#xff1a;ln -s 原文件名 新文件名 硬链接&#xff1a;ln 原文件名 新文件名 删除链接文件&#xff1a;unlink 文件名执行上面两条命令…

linux 简单使用 sftp 和 lftp命令

目录 一. 环境准备二. sftp命令连接到SFTP服务器三. lftp命令3.1 连接FTP和SFTP服务器3.2 将文件从sftp服务器下载到本地指定目录 四. 通过WinSCP命令行从SFTP服务器获取文件到Windows 一. 环境准备 ⏹在安卓手机上下载个MiXplorer&#xff0c;用作SFTP和FTP服务器 官网: htt…

MySQL数据库(一):数据库介绍与安装

在嵌入式开发中&#xff0c;数据库的重要性体现在高效的数据存储和管理、数据持久化、复杂查询和处理、数据同步和共享、安全性和可扩展性。常见嵌入式数据库包括SQLite、MySQL、LevelDB等&#xff0c;应用于智能家居、工业控制、车载系统和物联网设备&#xff0c;提升了系统功…