0

我有一个每分钟更新一次的数组。当我想在一天内显示它时,我想获得当天每小时的平均值。

最近一分钟是添加数组的末尾。

    //get the last elements from the array
    var hours= (this.today.getHours() + 1) * 60
    var data = Array.from(this.temps.data)
    let lastData = data.slice(Math.max(data.length - hours))

    let newData: any

    // calculate the average of every hour
    for (let i = 0; i < minutes; i++) {
      var cut = i * 60
      for (let i = cut; i < (cut + 60); i++) {
        newData = newData + lastData[i];
        let test = newData/60
        console.log(test);
      }
    }

我不知道如何从每最后 60 个元素中创建一个数组。我的目标是得到一个像

avgHour[20,22,30,27,]

我拥有的数组每分钟更新一次。所以我需要每 60 个元素的平均值来获得一个小时。

数组看起来像这样

data[25,33,22,33]

一周的每一分钟都非常长。

这对我有用

    var arrays = [], size = 60;

    while (arr.length > 0){
        arrays.push(arr.splice(0, size));
    }

    for (let i = 0; i < (arrays.length - 1); i++) {
      var sum = 0
        for (let b = 0; b < 60; b++) {
          sum += arrays[i][b]
        }
        let avg = sum/60
        arr2.push(avg)            
    }

这只是将数组每 60 个元素拆分一次。现在我可以计算每 60 个的平均值。How to split a long array into small arrays, with JavaScript

谢谢您的帮助!

4

4 回答 4

2

我是函数式编程库Ramda的忠实粉丝。(免责声明:我是它的作者之一。)我倾向于从简单的、可重用的函数的角度来思考。

当我想到如何解决这个问题时,我是从 Ramda 的角度来思考的。我可能会这样解决这个问题:

const avgHour = pipe(
  splitEvery(60),
  map(mean),
)

// some random data
const data = range(0, 7 * 24 * 60).map(_ => Math.floor(Math.random() * 20 + 10))

console.log(avgHour(data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {pipe, splitEvery, map, mean, range} = R</script>

我认为这是相当易读的,至少一旦您了解管道创建了一个函数管道,每个函数都将其结果传递给下一个函数。

现在,通常没有理由包含像 Ramda 这样的大型库来解决相当简单的问题。但是该版本中使用的所有功能都可以轻松重用。因此,尝试创建您自己的这些函数版本并让它们对您的应用程序的其余部分可用可能是有意义的。事实上,这就是像 Ramda 这样的库的实际构建方式。

所以这里有一个版本,对这些函数有简单的实现,你可以把它们放在实用程序库中:

const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x)
const splitEvery = (n) => (xs) => {
  let i = 0, a = [] 
  while (i < xs.length) {a.push(xs.slice(i, i + n)); i += n}
  return a
}
const map = (fn) => (xs) => xs.map(x => fn(x))
const sum = (xs) => xs.reduce((a, b) => a + b, 0)
const mean = (xs) => sum(xs) / (xs.length || 1)

const avgHour = pipe(
  splitEvery(60),
  map(mean)
)

const range = (lo, hi) => [...Array(hi - lo)].map((_, i) => lo + i)

// some random data
const data = range(0, 7 * 24 * 60).map(_ => Math.floor(Math.random() * 20 + 10))

console.log(avgHour(data))

于 2019-02-11T16:22:59.487 回答
1

您可以按小时减少数据和分组,然后简单地映射以获得每小时的平均值。我正在使用时刻来解析下面的日期,您可以使用您喜欢的任何 lib/js 来执行此操作...

const arr = Array.from({length: 100}, () => ({time: moment().subtract(Math.floor(Math.random() * 10), 'hours'), value: Math.floor(Math.random() * 100)}));

const grouped = [...arr.reduce((a, b) => {
    let o = a.get(b.time.get('hour')) || {value: 0, qty: 0};
    a.set(b.time.get('hour'), {value: o.value + b.value, qty: o.qty + 1});
    return a;
}, new Map)].map(([k, v]) => ({
    [k]: v.value / v.qty
}));




console.log(grouped)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment-with-locales.min.js"></script>

于 2019-02-11T15:24:54.560 回答
0

为了测量平均值,我需要每 60 个元素拆分一次数组。这是我找到的解决方案

//Calculate the average of every 60 elements to get the average of an hour
var arr2: number[] = []
var arr: number[] = []
arr = Array.from(this.temps.data)
var arrays = [], size = 60;

while (arr.length > 0){
    arrays.push(arr.splice(0, size));
}

for (let i = 0; i < (arrays.length - 1); i++) {
  var sum = 0
    for (let b = 0; b < 60; b++) {
      sum += arrays[i][b]
    }
    let avg = sum/60
    arr2.push(avg)            
}

毕竟我认为获取数组的最后一个元素是愚蠢的,因为这是一个更好的解决方案。但是感谢您的帮助!

于 2019-02-11T15:57:47.597 回答
0

通过分组然后减少,您可以执行以下操作。

function groupBy(list, keyGetter) {
  const map = {};
  list.forEach((item) => {
    const key = keyGetter(item);
    if (!map[key]) {
      map[key] = [item];
    } else {
      map[key].push(item);
    }
  });
  return map;
}

const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];

const now = (new Date()).getTime();

const stepSize = 60000*1;

const withTime = data.reverse().map((x, i) => { return { time: new Date(now - stepSize * i), temp: x } });

const grouped = groupBy(withTime, x => new Date(x.time.getFullYear(), x.time.getMonth(), x.time.getDate(), x.time.getHours()).valueOf());


const avg = Object.entries(grouped).map((x) => {
  return {
    time: new Date(Number(x[0])),
    temp: x[1].map(y => y.temp).reduce((acc, val) => acc + val) * (1.0 / x[1].length)
  }
});

console.log(avg);

于 2019-02-11T16:09:19.320 回答