EanX
EanX

Reputation: 505

Compute average of properties in objects array

Suppose to have an array of two or more objects as:

const arr =[{PM1:10, PM10:20},{PM1:20, PM10:30, CO:27}, {NO2:30}]

How can I efficiently compute average values for each property in the objects comprising the array? I don't know in advance the properties in each object and even if there are common properties. I would expect a result:

{PM1:15, PM10:25, CO:27, NO2:30}

I suppose that I can use reduce but I can't figure it out how.

Upvotes: 0

Views: 161

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1074495

You can loop through the property names of an object using either for-in (which includes inherited properties) or an array from Object.keys (which doesn't). In both cases, only enumerable properties are included.

For instance:

const arr =[{PM1:10, PM10:20},{PM1:20, PM10:30, CO:27}, {NO2:30}];

const result = {};
const counts = new Map();
for (const element of arr) {
    for (const key in element) {
        if (Object.hasOwn(element, key)) {
            // Count this property
            counts.set(key, (counts.get(key) ?? 0) + 1);
            // Add it to the sum
            result[key] = (result[key] ?? 0) + element[key];
        }
    }
}
// Update with the averages
for (const [key, count] of counts) {
    result[key] = result[key] / counts.get(key);
}

Live Example:

// Quick-and-dirty polyfill for older environments without `Object.hasOwn`:
if (!Object.hasOwn) {
    Object.defineProperty(Object, "hasOwn", {
        value: Function.prototype.call.bind(Object.prototype.hasOwnProperty),
        writable: true,
        configurable: true,
    });
}

const arr =[{PM1:10, PM10:20},{PM1:20, PM10:30, CO:27}, {NO2:30}];

const result = {};
const counts = new Map();
for (const element of arr) {
    for (const key in element) {
        if (Object.hasOwn(element, key)) {
            // Count this property
            counts.set(key, (counts.get(key) ?? 0) + 1);
            // Add it to the sum
            result[key] = (result[key] ?? 0) + element[key];
        }
    }
}
// Update with the averages
for (const [key, count] of counts) {
    result[key] = result[key] / counts.get(key);
}

console.log(result);

Upvotes: 1

Mister Jojo
Mister Jojo

Reputation: 22320

just 2 reduce...

const arr =
  [ { PM1:10, PM10:20}
  , { PM1:20, PM10:30, CO:27}
  , { NO2:30 }
  ]
const average =
  arr.reduce((a,c)=>
    {
    for(let key in c) 
      {
      let line = a.find( x=>x.k === key )
      if (!line) a.push( line = { k:key, sum:0, nb:0 } )
      line.sum += c[key]
      ++line.nb
      }
    return a
    },
  []).reduce((a,c)=>
    {
    a[c.k] = c.sum / c.nb
    return a
    },{})

console.log ( average )
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Related Questions