专栏首页grain先森前端-用 JS 写一个同 Excel 表现的智能填充算法

前端-用 JS 写一个同 Excel 表现的智能填充算法

作者:jrainlau https://segmentfault.com/a/1190000015951750

在使用Excel的时候,发现它的“智能填充”功能非常有趣,能够智能地分析我当前的内容,然后准确预测出我期望得到的值。排除了AI的加成,发现这个功能其实也可以通过数学理论和简单代码来实现。经过一番折腾,终于用JS实现了大致的功能,然后我把它名为 smart-predictor

项目地址:https://github.com/jrainlau/smart-predictor

什么是“智能填充”?

首先我们来看两张gif图:

是不是很神奇?假设我有一组给定的数据 [1,3,'aaa1','bbb2'],Excel的智能填充能够给我返回 [5,7,'aaa2','bbb3',9,11'aaa3','bbb4']这一组数据。

更厉害的是,智能填充不是简单地对数据进行递增,而是会对数据进行分组,每个分组按照自己的规则去进行递增,就比如说我们可以从 [1,2,'x',3]得到 [3,4,'x',4]

在明白这些结论之后,我们就可以去讨论它到底是怎么实现的。

Separator

我们用数组 [1,2,'a1c','a2c']作为例子。当我们拿到这样一个数组的时候,第一步是要对其进行分析,分析数组内每个元素到底是一个数字,一段字符串,还是别的什么东西。分析完了,就要给他们都标注更详细的信息,然后把这些信息都组合起来。

比如数组元素 1,可以被处理成下面这个样子:

{

 realValue: 1,

 numericValue: 1,

 splitParts: 'Number',

 index: 0

}

而数组元素 a1c,则可以处理成这样:

{

 realValue: 'a1c',

 numericValue: 1,

 splitParts: ['a', 'c'],

 index: 2

}

代码请戳:separator.js

可以注意到,我会提取每一个元素的纯数字部分出来,然后把其余部分通过一个数组储存起来。这一切就是 Separator所做的工作,我们最终会得到一个富含信息的新数组,然后继续我们的工作吧!

Classifier

智能填充的最小单位是“组”。当我们通过上一步得到一个富含信息的新数组之后,接下来就应该对它们进行合理的分组。分组的动作包含了两个细节:

1、同一组的数据应该拥有一致的“类型”,这里我们使用 splitParts属性去实现。

2、同一组的数据应该是连续的,否则的话就要把不连续的数据扔到一个新的组去。

假设有一个数组 [1,2,'a1c','a2c',6,8],元素 12就应该被分配到名为 Number的组去, a1ca2c则会被分配到名为 ac的组里面,而 68则会被另外分配到名为 Number1的新组里面去,最后结果如下:

{

 'Number': [{

   realValue: '1',

   ...

 }, {

   realValue: '2',

   ...

 }],

 'ac': [{

   realValue: 'a1c',

   ...

 }, {

   realValue: 'a2c',

   ...

 }],

 'Number1': [{

   realValue: '6',

   ...

 }, {

   realValue: '8',

   ...

 }]

}

代码请戳:classifier.js

通过上述步骤,我们成功把数据进行分组,组与组之间的元素并不会相互干扰。接下来我们需要实现一个专门做“线性回归”的方法,有了这个方法我们才能对数据进行“预测”。

Linear regression

“线性回归”是一个数学理论,详情请自己google之,这里我直接使用线性回归的二元一次公式去求得回归直线的斜率:

y = ax + b

a = ∑(x−x')(y−y') / ∑(x−x')(x−x')

其中 x'是所有点x坐标的平均数,同样的, y'是所有点y坐标的平均数。

代码请戳:linearRegression.js

通过这条公式,我们可以轻易得到数组 [1,3]的斜率和偏移量为 {a:2,b:1},然后就可以知道以后的数据走向将会是 [5,7,9,...]

这就是整一个“智能填充”的核心原理,接下来我们就可以依靠这个原理去实现数据的预测了。

Predictor

借助线性回归的力量,我们可以通过设置预测的次数,挨个挨个地对每一个分组数据进行预测,然后再把它们组合到一起形成一个新的结果数组。

以上文Classifier中的分组数据为例,对它预测一次,结果如下:

{

 'Number': [{

   realValue: '1',

   index: 0,

   ...

 }, {

   realValue: '2',

   index: 1,

   ...

 }, {

   realValue: '3',

   index: 6,

   ...

 }, {

   realValue: '4',

   index: 7,

   ...

 }],

 'ac': [{

   realValue: 'a1c',

   index: 2,

   ...

 }, {

   realValue: 'a2c',

   index: 3,

   ...

 }, {

   realValue: 'a3c',

   index: 8,

   ...

 }, {

   realValue: 'a4c',

   index: 9,

   ...

 }],

 'Number1': [{

   realValue: '6',

   index: 4,

   ...

 }, {

   realValue: '8',

   index: 5

   ...

 }, {

   realValue: '10',

   index: 10,

   ...

 }, {

   realValue: '12',

   index: 11

   ...

 }]

}

代码请戳:predictor.js

由于我们知道每一个数据的下标,所以我们可以简单又准确地把它们放到正确的位置去,最后输出如下:

[1, 2, 'a1c', 'a2c', 6, 8, 3, 4, 'a3c', 'a4c', 10, 12]

接下来我们可以来看看测试用例对比Excel表现:

More

当前的 smart-predictor仍然不够“smart”,它只能预测自然数字,或者自然数字与字符串的结合,但仍然不支持对日期格式,字母列表等数据的预测。如果各位读者有兴趣,也非常欢迎大家来贡献脑洞,让 smart-predicotr变得更加智能。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 加快 Vue 项目的开发速度

    Webpack是实现我们前端项目工程化的基础,但其实她的用处远不仅仅如此,我们可以通过Webpack来帮我们做一些自动化的事情。首先我们要了解require.c...

    grain先森
  • 前端-vue 和微信小程序的区别、比较

    写了vue项目和小程序,发现二者有许多相同之处,在此想总结一下二者的共同点和区别。

    grain先森
  • 前端-用 Vue 编写一个长按指令

    有没有想过创建一个按钮,按下一次就可以清除单次输入(或者持续按住可以清除所有输入)?

    grain先森
  • React 现代化测试

    测试用例的书写是一个风险驱动的行为, 每当收到 Bug 报告时, 先写一个单元测试来暴露这个 Bug, 在日后的代码提交中, 若该测试用例是通过的, 开发者就能...

    牧云云
  • Python学习笔记 - 02: 用Python Client连接ElasticSearch操作数据

    Python Elasticsearch Client 是 ES 官方推荐的 python 客户端,这里以它为工具操作 elasticsearch

    双面人
  • JNNP:脑小血管病的结构网络变化

    最近的一项关于脑小血管病(SVD)的纵向研究表明,白质结构脑网络的一个指标——“全局效率”与SVD患者的认知损伤关系密切,并且基线时段的全局效率还可以预测SV...

    用户1279583
  • nginx配置属性说明

    用户1220053
  • SysML 2019论文解读:推理优化

    随着机器学习和人工智能领域的持续发展,神经网络及其代表性的算法通过提升计算成本而实现了越来越高的准确度。量化(quantization)是一种以准确度为代价旨在...

    机器之心
  • 架构师必须掌握的 10 条设计原则

    函数是程序员的工具中最重要的抽象形式。它们能更多地被重复使用,你需要编写的代码就越少,代码也因此变得更可靠。较小的函数遵循单一职责原则更有可能被重复使用。

    java思维导图
  • Python暴力破解凯撒加密的文本

    凯撒加密是一种经典加密算法,把文本中的每个英文字母替换为字母表中后面第k个字母。该加密算法的抗攻击能力比较弱,因为密钥(也就是k)的取值范围是固定的,很容易暴力...

    Python小屋屋主

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动