Statistics
d3.min/d3.max/d3.extent
正常编写min的几种方式:
- for循环方式
const list = [2,4,1,4];
let min;
list.forEach((val, i) => {
if (i === 0) {
min = val;
} else if (val < min) {
min = val;
}
});
- 使用Math.min方式
const list = [2,4,1,4];
const min = Math.min(...list);
源码使用了类似for循环的方式. 需要注意的是: 比较的方式只是用大于/小于, 所以如果数组由字符串, 而非完全浮点数组成, min的结果可能不是所希望的.
extent的源码和min/max类似, 返回数组的[min, max]. 如果数组为空, 则返回[undefined, undefined].
d3.sum
求数组的和. 源代码使用for循环不断相加.
也可以使用reduce来实现sum:
const list = ['2',4,'11',4];
const sum = list.reduce((a, b) => (+a) + (+b));
d3.mean
求平均值. 会过滤非数值型. 这里首先需要判断非数值型:
isNaN(+val)
加号会将val转换为数值型. 如果不是数值型, 会转换为NaN.
过滤掉非数值型后, 使用sum / count即可.
d3.median
求中位数. 这里调用了d3.quantile来计算中位数.
d3.variance
求样本方差.
d3.deviation
求标准差.
Search
d3.scan
求给定数组的最小值, 但允许提供比较函数(这点不同于d3.min). 源代码中关键部分的代码:
while (++i < n) {
if (compare(xi = values[i], xj) < 0 || compare(xj, xj) !== 0) {
xj = xi, j = i;
}
}
- 将比较后的最小值存储在xj中, 然后索引递增进行排序.
- compare(xj, xj) !== 0用于过滤undefined, null和NaN.
const array = [{foo: 42}, {foo: 91}];
d3.scan(array, function(a, b) { return a.foo - b.foo; }); // 0
d3.scan(array, function(a, b) { return b.foo - a.foo; }); // 1
d3.bisector
这里使用了二分查找法:
left: function(a, x, lo, hi) {
if (lo == null) lo = 0;
if (hi == null) hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (compare(a[mid], x) < 0) lo = mid + 1;
else hi = mid;
}
return lo;
},
d3.ascending/d3.descending
比较两个数的大小.
export default function(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
JavaScript中NaN比较特殊, 它不能进行比较. 任何和NaN比较的操作均为false.