用JS写一个同Excel表现的智能填充算法
在使用Excel的时候,发现它的“智能填充”功能非常有趣,能够智能地分析我当前的内容,然后准确预测出我期望得到的值。排除了AI的加成,发现这个功能其实也可以通过数学理论和简单代码来实现。经过一番折腾,终于用JS实现了大致的功能,然后我把它名为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
智能填充的最小单位是“组”。当我们通过上一步得到一个富含信息的新数组之后,接下来就应该对它们进行合理的分组。分组的动作包含了两个细节:
- 同一组的数据应该拥有一致的“类型”,这里我们使用
splitParts
属性去实现。 - 同一组的数据应该是连续的,否则的话就要把不连续的数据扔到一个新的组去。
假设有一个数组[1, 2, 'a1c', 'a2c', 6, 8]
,元素1
和2
就应该被分配到名为Number
的组去,a1c
和a2c
则会被分配到名为ac
的组里面,而6
和8
则会被另外分配到名为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
变得更加智能。
相关推荐
-
认识原型对象和原型链 javascript/jquery
2019-5-6
-
使用 Angular 打造微前端架构的 ToB 企业级应用 javascript/jquery
2020-7-16
-
重构 – 用各种方式优化自己的函数库 javascript/jquery
2018-10-21
-
「开位」你所应该知道的HTTP——基础篇 javascript/jquery
2020-6-10
-
手写 Promise 原理,代码版 javascript/jquery
2019-10-3
-
Vue中key的作用 javascript/jquery
2020-7-11
-
购物车数字加减按钮HTML+CSS+JS(有需要嫌麻烦的小伙伴拿走不谢) javascript/jquery
2019-6-2
-
xss攻击执行原理分析 javascript/jquery
2019-9-1
-
JavaScript高阶副本:“==”隐藏下的类型转换 javascript/jquery
2019-4-14
-
JS 中 call 和 apply 的理解和使用 javascript/jquery
2019-8-15