1

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

2
  • break down the problem. #1 how to get the avg? Variable avg is gotten by for data in dataArray divided by dataArray.length. #2 do your other iteration(s) Commented Jan 22, 2019 at 4:54
  • 1
    What have attempted? Better you post that in your question. Commented Jan 22, 2019 at 5:01

6 Answers 6

4

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)

Sign up to request clarification or add additional context in comments.

Comments

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

6 Comments

I think he wants averaged values for each date.
How about "18 January 2019" and other dates that may come later?
@PrashantZombade make a function that takes a moment as an argument, call that function in a loop.
That will make unnecessary call to the functions to and fro. It might be good idea in this case to process the input in one go.
@PrashantZombade as other posters have suggested, use reduce()
|
0

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)

  

Comments

0

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 ]

Comments

0

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)

Comments

0

const sumRow = (sum, count) => ({ sum, count })

const summarize = data => data.reduce((a, c) => (prev => (
  { ...a, [c.moment]: sumRow(prev.sum + c.val, prev.count + 1) }
))(a[c.moment] || sumRow(0, 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 }
])))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.