Manipulate Array of objects

问题: I have an array of objects that appears as follows: var dataArray = [{ "moment": "18 January 2019", "val": 53 }, { "moment": "18 January 2019", "val": 69...

问题:

I have an array of objects that appears as follows:

var dataArray = [{ "moment": "18 January 2019", "val": 53 },
                 { "moment": "18 January 2019", "val": 69 },
                 { "moment": "18 January 2019", "val": 52 },
                 {"moment": "21 January 2019", "val": 52 },
                 { "moment": "21 January 2019", "val": 52 },
                 { "moment": "21 January 2019", "val": 52 }]

What I would like to do is to put in a new array the value of the element moment and the average of val for that moment. eg:

result =[{moment: "18 January 2019", "val": 58},
{moment: "21 January 2019", "val": 52}].

For now I managed to put a single occurence of each date in the new array result but I am having hard time to put the average since I don't know how to make the difference between values for a date from values for another date. Any help would be appreciated.

Peace


回答1:

You can do it using reduce.

Here first we aggregate the values by moment and also count no. of similar moments. and than map through it and find the average using the aggregated value and count.

var dataArray = [{ "moment": "18 January 2019","val": 53 },{ "moment": "18 January 2019", "val": 69 },{ "moment": "18 January 2019", "val": 52 },{"moment": "21 January 2019", "val": 52 },                { "moment": "21 January 2019", "val": 52 },                { "moment": "21 January 2019", "val": 52 }]
                 
let output = dataArray.reduce((op,cur)=>{
  if( op[cur.moment] ){
    op[cur.moment].val += cur.val;
    op[cur.moment].count++;
  } else {
    op[cur.moment] = cur
    op[cur.moment].count = 1;
  }
  return op;
},{})

let final = Object.values(output).map(e => {
   return {
    moment: e.moment,
    val: e.val/e.count
   } 
})

console.log(final)


回答2:

var totalCount = 0;
var divBy = 0;
var momentToCheck = "21 January 2019"
for(int i= 0; i<dataArray.length; i++) {
    if (dataArray[i].moment === momentToCheck) {
        totalCount+= dataArray[i].val;
        divBy++;
    }
}
var newAvg = totalCount/divBy;
dataArray.push({moment:momentToCheck, val:newAvg});

回答3:

It might make sense to first perform a grouping, and then to perform the average of each group. For example:

const dataArray = [{ "moment": "18 January 2019", "val": 53 },
                   { "moment": "18 January 2019", "val": 69 },
                   { "moment": "18 January 2019", "val": 52 },
                   { "moment": "21 January 2019", "val": 52 },
                   { "moment": "21 January 2019", "val": 52 },
                   { "moment": "21 January 2019", "val": 52 }]
                   
const groups = dataArray.reduce((r, { moment, val }) => {
  (r[moment] = r[moment] || []).push(val)  
  return r
}, {})

const avg = arr => arr.reduce((r, x) => r + x, 0) / arr.length

const result = Object.entries(groups).map(([moment, arr]) => ({
  moment,
  avg: avg(arr)
}))

console.log(result)

  


回答4:

You can achieve the expected result in the following way using reduce

var dataArray = [{
        "moment": "18 January 2019",
        "val": 53
    },
    {
        "moment": "18 January 2019",
        "val": 69
    },
    {
        "moment": "18 January 2019",
        "val": 52
    },
    {
        "moment": "21 January 2019",
        "val": 52
    },
    {
        "moment": "21 January 2019",
        "val": 52
    },
    {
        "moment": "21 January 2019",
        "val": 52
    }
];

const result = dataArray.reduce((accumulator, currentValue, index, array) => {
    if (!accumulator[currentValue.moment]) {
        accumulator[currentValue.moment] = array
            .filter(arr => arr.moment === currentValue.moment)
            .reduce((acc, val, idx, coll) => {
                acc += val.val;

                if (idx === coll.length - 1) {
                    return acc/coll.length;
                } else {
                    return acc;
                }
        }, 0);
    }

    return accumulator;
}, []);

console.log(result); // [ '18 January 2019': 58, '21 January 2019': 52 ]

回答5:

Use array reduce and inside the call back check if the arument array have moment with same value

var dataArray = [{
    "moment": "18 January 2019",
    "val": 53
  },
  {
    "moment": "18 January 2019",
    "val": 69
  },
  {
    "moment": "18 January 2019",
    "val": 52
  },
  {
    "moment": "21 January 2019",
    "val": 52
  },
  {
    "moment": "21 January 2019",
    "val": 52
  },
  {
    "moment": "21 January 2019",
    "val": 52
  }
]

let avgVal = dataArray.reduce(function(acc, curr) {
  let findIfHasDate = acc.findIndex((item) => {
    return item.moment === curr.moment

  });

  if (findIfHasDate === -1) {
    acc.push({
      moment: curr.moment,
      totalVal: curr.val,
      totalcount: 1

    })
  } else {
    acc[findIfHasDate].totalVal = (acc[findIfHasDate].totalVal + curr.val);
    acc[findIfHasDate].totalcount += 1;
  }

  return acc;
}, []).map((item) => {
  return {
    moment: item.moment,
    avg: (item.totalVal) / item.totalcount
  }
})

console.log(avgVal)


回答6:

const summarize = data => data.reduce(
  (a, c) => (prev => (
    { ...a, [c.moment]: { sum: (prev.sum + c.val), count: (prev.count + 1) } }
  ))(a[c.moment] || { sum: 0, count: 0 }), 
  {}
)

const average = summary => Object.keys(summary).map(
  k => ({ moment: k, val: (summary[k].sum / summary[k].count) })
)
 
console.log(average(summarize([
  { "moment": "18 January 2019", "val": 53 },
  { "moment": "18 January 2019", "val": 69 },
  { "moment": "18 January 2019", "val": 52 },
  { "moment": "21 January 2019", "val": 52 },
  { "moment": "21 January 2019", "val": 52 },
  { "moment": "21 January 2019", "val": 52 }
])))

  • 发表于 2019-01-23 07:21
  • 阅读 ( 189 )
  • 分类:网络文章

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除