根据顺序返回可迭代对象中的最小值,如果没有可以比较的值,返回undefined. 可选访问函数等价于调用Array.from(Array.from用法,将类似于数组的对象转化为数组,要求该对象有length属性)。
和Math.min不同,该方法会会忽略undefined,null,NaN值,这对处理missing data有用, 此外,元素比较顺序依赖字符串顺序而不是数字顺序,比如,["20","3"]按照字符串顺序最小值为“20”,[20,3]按照数字顺序最小值为3。
export default function min(values, valueof) {
let min;
if (valueof === undefined) {
for (let value of values) {
if (value != null
&& value >= value
&& (min === undefined || min > value)) {
min = value;
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null
&& value >= value
&& (min === undefined || min > value)) {
min = value;
}
}
}
return min;
}
采用ES6 module标准导出接口,这里value >= value 操作有点不解?
该方法返回最大值,其他特性与d3.min类似。
export default function max(values, valueof) {
let max;
if (valueof === undefined) {
for (let value of values) {
if (value != null
&& value >= value
&& (max === undefined || max < value)) {
max = value;
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null
&& value >= value
&& (max === undefined || max < value)) {
max = value;
}
}
}
return max;
}
该方法返回[最小值,最大值],没有可比较元素返回[undefined,undefined]。
export default function(values, valueof) {
let min;
let max;
if (valueof === undefined) {
for (let value of values) {
if (value != null && value >= value) {
if (min === undefined) {
min = max = value;
} else {
if (min > value) min = value;
if (max < value) max = value;
}
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null && value >= value) {
if (min === undefined) {
min = max = value;
} else {
if (min > value) min = value;
if (max < value) max = value;
}
}
}
}
return [min, max];
}
实现原理没有什么特别的,第一次循环将value赋值min,max,后面循环求出最大值最小值。
d3.sum(iterable[, accessor])
返回可迭代元素和,如果没有元素返回0。该方法忽略undefine,NaN。
export default function sum(values, valueof) {
let sum = 0;
if (valueof === undefined) {
for (let value of values) {
if (value = +value) {
sum += value;
}
}
} else {
let index = -1;
for (let value of values) {
if (value = +valueof(value, ++index, values)) {
sum += value;
}
}
}
return sum;
}
这里value前的+号,作用是什么?
返回平均值,忽略undefine,NaN。
export default function mean(values, valueof) {
let count = 0;
let sum = 0;
if (valueof === undefined) {
for (let value of values) {
if (value != null && (value = +value) >= value) {
++count, sum += value;
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
++count, sum += value;
}
}
}
if (count) return sum / count;
}
使用r-7method返回中位数
import quantile from "./quantile.js";
import quickselect from "./quickselect.js";
function* numbers(values, valueof) {
if (valueof === undefined) {
for (let value of values) {
if (value != null && (value = +value) >= value) {
yield value;
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
yield value;
}
}
}
}
export default function(values, valueof) {
values = Float64Array.from(numbers(values, valueof));
if (!values.length) return;
const n = values.length;
const i = n >> 1;
quickselect(values, i - 1, 0);
if ((n & 1) === 0) quickselect(values, i, i);
return quantile(values, 0.5);
}
首先通过迭代器函数生成float64数组,通过quickselect给中值排好序。
该方法为Floyd–Rivest algorithm,快速选择算法。
详情:https://en.wikipedia.org/wiki/Floyd%E2%80%93Rivest_algorithm
import ascending from "./ascending.js";
// Based on https://github.com/mourner/quickselect
// ISC license, Copyright 2018 Vladimir Agafonkin.
export default function quickselect(array, k, left = 0, right = array.length - 1, compare = ascending) {
while (right > left) {
if (right - left > 600) {
const n = right - left + 1;
const m = k - left + 1;
const z = Math.log(n);
const s = 0.5 * Math.exp(2 * z / 3);
const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
const newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
quickselect(array, k, newLeft, newRight, compare);
}
const t = array[k];
let i = left;
let j = right;
swap(array, left, k);
if (compare(array[right], t) > 0) swap(array, left, right);
while (i < j) {
swap(array, i, j), ++i, --j;
while (compare(array[i], t) < 0) ++i;
while (compare(array[j], t) > 0) --j;
}
if (compare(array[left], t) === 0) swap(array, left, j);
else ++j, swap(array, j, right);
if (j <= k) left = j + 1;
if (k <= j) right = j - 1;
}
return array;
}
function swap(array, i, j) {
const t = array[i];
array[i] = array[j];
array[j] = t;
}
这个算法有点复杂,功能为快速选择k值的算法。如果数据量过大,会先选择一个样本进行就行搜索。首先对第在k的位置上的值放置到该值应该呆的位置,之后根据k位置的值所在的下标进行更新,取前部或着取后部,循环迭代直到找到了第k值。
x为null返回NaN,否则返回x,该函数的功能就是可以把字符串变成数字,+“123”=123。
export default function(x) {
return x === null ? NaN : +x;
}
import number from "./number.js";
export default function quantile(values, p, valueof = number) {
if (!(n = values.length)) return;
if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values);
if (p >= 1) return +valueof(values[n - 1], n - 1, values);
var n,
i = (n - 1) * p,
i0 = Math.floor(i),
value0 = +valueof(values[i0], i0, values),
value1 = +valueof(values[i0 + 1], i0 + 1, values);
return value0 + (value1 - value0) * (i - i0);
}
用法如下,当然要求传入的数组为排好序的数组
var a = [0, 10, 30];
d3.quantile(a, 0); // 0
d3.quantile(a, 0.5); // 10
d3.quantile(a, 1); // 30
d3.quantile(a, 0.25); // 5
d3.quantile(a, 0.75); // 20
d3.quantile(a, 0.1); // 2
export default function variance(values, valueof) {
let count = 0;
let delta;
let mean = 0;
let sum = 0;
if (valueof === undefined) {
for (let value of values) {
if (value != null && (value = +value) >= value) {
delta = value - mean;
mean += delta / ++count;
sum += delta * (value - mean);
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
delta = value - mean;
mean += delta / ++count;
sum += delta * (value - mean);
}
}
}
if (count > 1) return sum / (count - 1);
}
使用增量算法计算方差:https://www.cnblogs.com/yoyaprogrammer/p/delta_variance.html
import variance from "./variance.js";
export default function deviation(values, valueof) {
const v = variance(values, valueof);
return v ? Math.sqrt(v) : v;
}
标准差即对方差开根号
对可迭代对象执行线性迭代,根据可选比较函数comparator返回最小元素的索引,(如果比较函数返回NaN,即给定的对象没有可以比较的元素,该函数返回undefined,比较函数没有指定,默认为ascending).例如:
const array = [{foo: 42}, {foo: 91}];
d3.scan(array, (a, b) => a.foo - b.foo); // 0
d3.scan(array, (a, b) => b.foo - a.foo); // 1
该方法和min非常类似,区别就是该方法接受一个比较函数而不是访问函数,返回元素为下标。
import ascending from "./ascending.js";
export default function scan(values, compare = ascending) {
let min;
let minIndex;
let index = -1;
for (const value of values) {
++index;
if (minIndex === undefined
? compare(value, value) === 0
: compare(value, min) < 0) {
min = value;
minIndex = index;
}
}
return minIndex;
}
该比较函数为natural order,递增顺序。可以与内置的array.sort方法一起使用,以按升序排列元素。
export default function(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
这里要注意array.sort在没有指定比较函数的情况下,默认排序为字典顺序(lexicographic),而不是natural。
ES6标准引入iterable类型,Array、Map、Set都属于iterable类型,可以使用for...of循环来遍历。
了解更多:https://www.cnblogs.com/yuanxinru321/p/7551660.html
关于Set:https://www.cnblogs.com/diligenceday/p/5479076.html
Array.from方法:https://www.jianshu.com/p/f4554f74de95
通过next()方法调用yield,返回两个值,value和done,分别为本次的返回值和后续是否还有yield语句布尔值。yield*可以移交执行权。
了解更多:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/function*