const sum = xs => xs.reduce((a, b) => a + b, 0)
const stats = data => data.reduce( 
    ({count, sum, mean, vari, min, max}, x) => {
      const k = 1 / (count + 1)
      const mean_ = mean + k * (x - mean)
      const ssr_ = (count - 1) * vari + k * count * (x - mean) * (x - mean)
      return {
          count: count + 1
          , sum: sum + x
          , mean: mean_
          , vari: ssr_ / Math.max(1, count)
          , min: isNaN(min) || x < min ? x : min
          , max: isNaN(max) || x > max ? x : max
      }
    }
    , {count: 0, sum: 0, mean: 0, vari: 0, min: NaN, max: NaN}
)
const stats_classic = data => {
    const dsum = sum(data)
    const dmean = dsum / data.length
    const sum_sq_dist = sum(data.map(d => (d - dmean) * (d - dmean)))
    return {
        count: data.length,
        sum: dsum,
        mean: dmean,
        vari: sum_sq_dist / data.length,
        tvari: sum_sq_dist / (data.length - 1)
    }
}
console.log(
    stats([3,4,2,2,4,3,2,2,-3,4,5])
)
console.log(
    stats_classic([3,4,2,2,4,3,2,2,-3,4,5])
)
const fromPairs = pairs => pairs.reduce((acc, [k, v]) => { acc[k] = v; return acc }  , {})
const statsp = props => data => data.reduce( 
  (acc, a) => fromPairs(props.map(p => {
    const {count, sum, mean, vari, min, max} = acc[p]
    const x = a[p]
    const k = 1 / (count + 1)
    const mean_ = mean + k * (x - mean)
    const ssr_ = (count - 1) * vari + k * count * (x - mean) * (x - mean)
    return [p, {
                 count: count + 1
               , sum: sum + x
               , mean: mean_
               , vari: ssr_ / Math.max(1, count)
               , min: isNaN(min) || x < min ? x : min
               , max: isNaN(max) || x > max ? x : max
           }]
  }))
  , fromPairs(props.map(p => [p, {count: 0, sum: 0, mean: 0, vari: 0, min: NaN, max: NaN}]))
)
const props = ['views']
console.log(
    statsp(props)([3,4,2,2,4,3,2,2,4,5].map(views => ({views})))
)