【问题标题】:Average of every hour in a array数组中每小时的平均值
【发布时间】:2019-07-05 02:58:33
【问题描述】:

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

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

    //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 smaller arrays, with JavaScript的副本

感谢您的帮助!

【问题讨论】:

  • 您有一些数据要测试以及您的期望吗?
  • 如果你可以包含lodash,它有一个名为chunk 的函数,它接受一个数组并将它拆分为你想要的任何子数组。 lodash.com/docs/4.17.11#chunk
  • 只需 push test 到循环外的新数组就完成了吗?

标签: javascript typescript


【解决方案1】:

您可以减少数据并按小时分组,然后简单地映射以获得每小时的平均值。我正在使用 moment 来解析下面的日期,你可以用你喜欢的任何 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)
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment-with-locales.min.js"&gt;&lt;/script&gt;

【讨论】:

  • 请注意,请求的输入格式只是一个整数列表,而不是带有时间戳的对象。
  • 这段代码属于垃圾,带有一些危险警告
  • 你有什么不明白的@JurajKocan
  • [...arrr.reduce()].map().filter().find() 这是不可读的代码...让 o 让 b 另一个大错误...当然我可以阅读它并找到它的作用。但是当我看它的时候。我只是不会
【解决方案2】:

为了测量我需要每 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)            
}

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

【讨论】:

  • 这对您来说可能根本不重要,但是这个版本对您的原始阵列具有破坏性。你可能想先做一个浅层克隆,var newArr = arr.slice(0),然后再拼接那个。
  • 不,没关系,因为我已经将它从原始对象复制到数组中。我更新了我的代码。但是看看几秒钟还是不错的,因为它可能会破坏我的代码。
【解决方案3】:

通过分组然后减少你可以这样做。

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);

【讨论】:

  • 请注意,请求的输入格式只是一个整数列表,而不是带有时间戳的对象。
  • @ScottSauyet 错过了这一点。现在它应该可以工作了,但首先生成时间,在这种情况下可能不是最好的解决方案?
【解决方案4】:

我是函数式编程库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))

【讨论】:

    猜你喜欢
    • 2017-11-12
    • 2015-03-12
    • 1970-01-01
    • 1970-01-01
    • 2015-11-07
    • 1970-01-01
    • 2012-08-17
    • 2022-07-15
    • 1970-01-01
    相关资源
    最近更新 更多