【问题标题】:JavaScript arrays - efficiently calculate average in given intervalsJavaScript 数组 - 有效计算给定间隔内的平均值
【发布时间】:2016-08-04 18:43:32
【问题描述】:

我有两个数组,一个代表数据,另一个代表区间。两者都已排序,并且它们的开始值和结束值匹配。我通过嵌套的 for 循环来计算给定间隔内数据点的平均值。结果,我最终得到每个间隔的一个数据值。对于小于 100-500 长度的较小尺寸的数组,这些线性循环可以完成工作,但是,这种方法会成为数千个数据点的问题。任何建议将不胜感激。

请看下面的简化代码,末尾有 JSfiddle 的链接

var TimelineArray = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100],
	DataArray = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100],
	DataArrayA = [];

for (i = 0; i < TimelineArray.length-1; i++) {
	var dataPointsInGivenTimeInterval = [];
	for (j = 0; j < DataArray.length; j++) {
		if (DataArray[j] > TimelineArray[i] && DataArray[j] <= TimelineArray[i+1]) {
			dataPointsInGivenTimeInterval.push(DataArray[j]);
		}
	};
	if (dataPointsInGivenTimeInterval.length == 0) {
		DataArrayA.push(null);
	}
	else {
		var sumOfdataPoints = null;
		for (k = 0; k < dataPointsInGivenTimeInterval.length; k++) {
			sumOfdataPoints += dataPointsInGivenTimeInterval[k];
		}
		var avg = sumOfdataPoints / dataPointsInGivenTimeInterval.length;
		DataArrayA.push(avg);
	}
} // end for

console.log(TimelineArray);
console.log(DataArrayA);
.as-console-wrapper {
  max-height: 100% !important;
  top: 0;
}

控制台输出是

[0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100]
[4.75, 15, 25.25, 36, null, 56.2, 64, 75, 89, 95]

这是 JSfiddle 的代码 - calculating average values for given intervals

【问题讨论】:

  • 如果有帮助,我有一个简单的解决方案可以从数组中获取平均值?以及将此类函数添加到数学对象的复杂函数?
  • github.com/JDMcKinstry/Math.Extensions 使用 Math.average([0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100]) 结果为 49.09090909090909
  • TimelineArray 元素之间的间隔是否总是相同(在本例中为 10)?
  • 间隔总是相同的,但是,每个间隔的数据点数会有所不同 - 从 0(例如,示例中的一个间隔中的空值)到任何数字。这就是为什么我保留一个临时数组 dataPointsInGivenTimeInterval 来存储然后计算平均值。

标签: javascript arrays algorithm average


【解决方案1】:

由于数组已排序,您可以根据时间线和数据的大小线性进行:

var timeline = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100],
    data = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100];
var averages = new Array(timeline.length - 1);
for (var i = 0, j = 0; i < timeline.length; i++) {
  var sum = 0,
      items = 0;
  for (; data[j] <= timeline[i]; j++) {
    sum += data[j];
    ++items;
  }
  if(i) averages[i-1] = sum / items;
}
console.log(averages);
.as-console-wrapper {
  max-height: 100% !important;
  top: 0;
}

【讨论】:

    【解决方案2】:

    您无需在每次迭代时从头重新扫描DataArray

    var TimelineArray = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100];
    var DataArray = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100];
    
    var res = [], pos = 0;
    
    TimelineArray.forEach(function(v, i) {
      for(var sum = 0, n = 0; DataArray[pos] <= v; n++) {
        sum += DataArray[pos++];
      }
      i && res.push(n ? sum / n : null);
    });
    
    console.log(res);

    【讨论】:

    • 我喜欢在每次迭代时不从头扫描整个数据数组的想法。结尾部分呢?我相信同样的想法可以应用于同一个数据数组的结束标签。一旦数据值变得大于循环中给定区间的右边缘,那么很明显数据数组的其余部分也会更大。所以它们也可以忽略。
    • 请注意,@Oriol 用一个非常相似的解决方案击败了我 10 分钟,也没有从一开始就重新扫描。 ^^ 不确定在最后部分理解你的想法。它不适用于您的示例数据集,因为两个数组都以 100 结尾,对吗?
    • 好的,实际上它已经存在了,我只是错过了它,在@Oriol 的代码中,嵌套循环的条件与我提到的一样(; data[j]
    【解决方案3】:

    不确定它是否会更快,但这里有一个不同的方法:

    var TimelineArray = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100],
    DataArray = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100],
    DataArrayA = [];
      
    function avg(arr){
      if(arr!= null && arr.length > 0)
        return arr.reduce(function(a, b){ return a+b;}, 0) / arr.length;
      return null;
    }
    for(var i = 0; i < TimelineArray.length-1; i++){
      var interval = [TimelineArray[i], TimelineArray[i+1]];
      var data = DataArray.filter(function(a){ return a > interval[0] && a <= interval[1]});
      DataArrayA.push(avg(data));
    }
    
    console.log(DataArrayA);

    编辑 1:删除了一个循环。

    【讨论】:

      猜你喜欢
      • 2019-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-10
      • 1970-01-01
      • 2021-02-08
      相关资源
      最近更新 更多