JS中用于FEN DFA状态转换的33分支switch语句如何优化更简洁?
JS DFA代码优化方案
核心优化:替换33分支switch语句
你不需要写长长的switch分支,只需要预先建立字符到DFA列索引的映射表,1行代码就能完成状态转移:
- 先定义所有FEN合法字符和对应列索引的映射对象:
// 按你自己的字符顺序填充全33个字符即可,这里举前几个的例子 const charToDfaCol = { 'r': 0, 'n': 1, 'b': 2, 'q': 3, 'k': 4, 'p': 5, // 剩下的27个FEN字符按你自己的列顺序补全 }
- 循环里直接查表获取列索引,完成状态转移,完全不需要switch:
// 注意不要用for...in遍历字符串,会遍历到非字符属性,改用for...of for (const char of fen) { const col = charToDfaCol[char] // 可以加个非法字符判断,遇到不在字符集里的字符直接终止 if (col === undefined) { dfarow = -1 // 标记为非法状态 break } dfarow = dfa[dfarow][col] }
接受状态的优化建议
不建议把接受状态标识塞到DFA转移数组的第34列,会让转移数组职责不清晰,更干净的写法是单独维护接受状态集合:
// 比如你最终的接受状态是2,就直接加进去 const acceptStates = new Set([2]) // 判断是否合法时直接查集合 const isAccept = acceptStates.has(dfarow)
如果你坚持要放在数组里也可以,只是单独维护接受状态的扩展性更好,后续新增接受状态不需要修改DFA转移数组本身。
其他优化点
- 遍历字符串不要用
for...in,这是用来遍历对象可枚举属性的,遍历字符串用for...of或者普通for循环调用charAt()更稳妥,避免拿到非字符的额外属性 - 可以提前做DFA数组的边界校验,避免索引越界报错
- 如果追求极致性能,可以把字符映射表换成ASCII码索引的数组,用
char.charCodeAt(0)获取字符编码直接查数组,比对象属性查找速度略快,不过33个元素的场景下差别可以忽略
完整优化后示例代码
// 先定义全局的字符映射表,按你自己的字符顺序补全 const CHAR_TO_COL = { 'r': 0, 'n': 1, 'b': 2, 'q': 3, 'k': 4, 'p': 5, // 补全剩余27个FEN合法字符:大写RNBQKP、数字1-8、/、w、b、-、KQkq等 } const ACCEPT_STATES = new Set([2]) // 替换成你自己的接受状态 function FEN2datumType(fen, dfa) { let dfarow = 0 // 起始状态,记得加let避免变成全局变量 for (const char of fen) { const col = CHAR_TO_COL[char] if (col === undefined) { dfarow = -1 break } dfarow = dfa[dfarow]?.[col] ?? -1 // 可选链加空值合并避免越界报错 if (dfarow === -1) break } return ACCEPT_STATES.has(dfarow) }
内容的提问来源于stack exchange,提问作者cubesareneat
相关产品推荐
相关产品推荐

