我正试图以功能的方式做到这一点,所以尽管有一些方法我已经可以想到,但我怀疑有更优雅的map / reduce风格技术。
给出这样的数组:
[0, 47.22, 72.65, 126.93, 155.02, 307.46, 410.02, 417.21,
507.86, 510.466, 580.88, 661.29, 685.14, 695.86, 780.94,
913.2, 1352.33, 1382.99, 1435.73, 1462.03, 1495.38, 1518.03,
1523.58, 1544.3, 1591.21, 1612.03, 1665.99, 1672.62, 11.02, 22.791]
我想计算每个项目及其后续值之间的差异,例如:
[47.22, 25.43, 54.28] // etc
(这些值是聊天消息的时间戳 - 我想有效地查看消息之间的差距,然后计算该用户的平均值。)
我在看reduce()
但是很难看到如何让它做我需要的事情。有没有一种优雅的方法来做到这一点,或者我最好的选择是for
循环,它会向前看下一个数组项并在那里进行计算?
答案 0 :(得分:4)
使用reduce
的另一种解决方案。当平均值不可计算时,此函数返回合理的NaN
结果。
此数据计算出0.7858965517241373
的错误答案,因为输入数据是无序的,这是没有意义的。如果您对数据进行排序,则会得到更明智的31.48965517241379
秒平均增量。
const averageDelta = ([x,...xs]) => {
if (x === undefined)
return NaN
else
return xs.reduce(
([acc, last], x) => [acc + (x - last), x],
[0, x]
) [0] / xs.length
};
let timestamps = [
0, 47.22, 72.65, 126.93, 155.02, 307.46, 410.02, 417.21,
507.86, 510.466, 580.88, 661.29, 685.14, 695.86, 780.94,
913.2, 1352.33, 1382.99, 1435.73, 1462.03, 1495.38, 1518.03,
1523.58, 1544.3, 1591.21, 1612.03, 1665.99, 1672.62, 11.02, 22.791
]
console.log(averageDelta(timestamps)) // 0.7858965517241373
console.log(averageDelta(timestamps.sort())) // 31.48965517241379
但是您使用functional-programming
标记了此问题,因此您可能正在寻找更好的解决方案。上面的答案很好,但它混合了几个基本算术计算的问题。 averageDelta
在一个函数中计算差异, sum 和均值 - 这真是一团糟!
下面我们将分别为每个事项实现一个函数,这样我们就不必那么认真。您还会注意到我已经注意确保每个函数都是total function,该函数适用于其域的所有输入。这意味着average
和delta
将为空数组,单数组数组以及具有多个数字的数组返回合理的结果。
const add = (x,y) =>
x + y
const sum = xs =>
xs.reduce(add, 0)
const average = xs =>
xs[0] === undefined ? NaN : sum(xs) / xs.length
const delta = ([x,...xs]) =>
xs.reduce(([acc, last], x) => [[...acc, x-last], x], [[], x]) [0]
let timestamps = [
0, 47.22, 72.65, 126.93, 155.02, 307.46, 410.02, 417.21,
507.86, 510.466, 580.88, 661.29, 685.14, 695.86, 780.94,
913.2, 1352.33, 1382.99, 1435.73, 1462.03, 1495.38, 1518.03,
1523.58, 1544.3, 1591.21, 1612.03, 1665.99, 1672.62, 11.02, 22.791
]
console.log(average(delta([]))) // NaN
console.log(average(delta([1]))) // NaN
console.log(average(delta(timestamps))) // 0.7858965517241373
console.log(average(delta(timestamps.sort()))) // 31.48965517241379
警告:
timestamps.sort()
使用Array.prototype.sort
来改变原始数组。考虑到在原始帖子中没有讨论排序,我会将其作为一个问题让你解决,如果它甚至是一个。
答案 1 :(得分:1)
您可以使用reduce()
这样做。
var data = [0, 47.22, 72.65, 126.93, 155.02, 307.46, 410.02, 417.21,
507.86, 510.466, 580.88, 661.29, 685.14, 695.86, 780.94,
913.2, 1352.33, 1382.99, 1435.73, 1462.03, 1495.38, 1518.03,
1523.58, 1544.3, 1591.21, 1612.03, 1665.99, 1672.62, 11.02, 22.791];
var result = data.reduce(function(r, e, i) {
if(data[i+1]) r.push(Number((data[i+1] - e).toFixed(2)));
return r;
}, [])
console.log(result)

答案 2 :(得分:1)
您可以使用Array#reduce
并仅使用前一个值。
var array = [0, 47.22, 72.65, 126.93, 155.02, 307.46, 410.02, 417.21, 507.86, 510.466, 580.88, 661.29, 685.14, 695.86, 780.94, 913.2, 1352.33, 1382.99, 1435.73, 1462.03, 1495.38, 1518.03, 1523.58, 1544.3, 1591.21, 1612.03, 1665.99, 1672.62, 11.02, 22.791],
delta = array.reduce(function (r, a, i, aa) {
i && r.push(a - aa[i - 1]);
return r;
}, []),
average = delta.reduce(function (a, b) { return a + b; }) / delta.length;
console.log(delta);
console.log(average);

.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 3 :(得分:1)
您可以使用map
并返回当前和下一个项目之间的差异
var arr = [0, 47.22, 72.65, 126.93, 155.02, 307.46, 410.02, 417.21,
507.86, 510.466, 580.88, 661.29, 685.14, 695.86, 780.94,
913.2, 1352.33, 1382.99, 1435.73, 1462.03, 1495.38, 1518.03,
1523.58, 1544.3, 1591.21, 1612.03, 1665.99, 1672.62, 11.02, 22.791];
var output = arr.map( function( item, index, arr ){
return (arr[index+1] - arr[index]);
});
output.splice(-1,1); //remove last item, it is NaN since it is a difference between undefined and 22.791
console.log("Diff is", output);
var average = output.reduce( function(curr,prev){ return curr+prev; })/output.length;
console.log("average", average);
答案 4 :(得分:1)
使用forEach
循环将相邻元素之间的差异添加到新数组中:
var arr = [22, 47.22, 72.65, 126.93, 155.02, 307.46, 410.02, 417.21, 507.86, 510.466, 580.88, 661.29, 685.14, 695.86, 780.94,913.2, 1352.33, 1382.99, 1435.73, 1462.03, 1495.38, 1518.03,1523.58, 1544.3, 1591.21, 1612.03, 1665.99, 1672.62, 11.02, 22.791];
var result = {array:[], sum: 0, current: 0};
arr.forEach(function(element, index, array) {
this.current = ((array[index + 1] - element) || 0);
this.sum += this.current;
this.array.push(this.current.toFixed(3));
}, result);
console.log(result.array);
console.log("Average: ", (result.sum / result.array.length).toFixed(3));
.as-console-wrapper{top:0;max-height:100%!important;}
修改强>:
感谢@naomik提出建议 - 更好地使用reduce
将所有突变保留在回调本地
var arr = [0, 47.22, 72.65, 126.93, 155.02, 307.46, 410.02, 417.21, 507.86, 510.466, 580.88, 661.29, 685.14, 695.86, 780.94,913.2, 1352.33, 1382.99, 1435.73, 1462.03, 1495.38, 1518.03,1523.58, 1544.3, 1591.21, 1612.03, 1665.99, 1672.62, 11.02, 22.791];
var result = arr.reduce(function(acc, element, index, array) {
acc.sum += element - acc.prev;
index && acc.array.push((element - acc.prev).toFixed(3));
acc.prev = element;
return acc;
}, {array:[], sum: 0, prev: arr[0]});
console.log(result.array);
console.log("Average: ", (result.sum / result.array.length).toFixed(3));
.as-console-wrapper{top:0;max-height:100%!important;}