1

I have a javascript object, and array of id's:

var ids = [46,44,49,47];
var obj = {
        "46": {
            "group": "A",
            "temp": 26,
            "humid": 36
        },
        "44": {
            "group": "B",
            "temp": 19,
            "humid": 32
        },
        "49": {
            "group": "B",
            "temp": 20,
            "humid": 31
        },
        "47": {
            "group": "A",
            "temp": 24,
            "humid": 32
        }
    };

I want to get the average 'temp' of each 'group'. How can I do this?

I found other examples that would solve this problem, however, these examples assume that 'group' will always be the same. In my case, 'group' is always changing.

So essentially I need to find how many unique groups exist, then return the average 'temp' value of each.

I attempted to use some for loops nested together, but it got complicated quickly...

Expected Output: avgTemps = {"A":25, "B": 19.5}

4
  • 2
    What is the expected output? Commented Jul 11, 2021 at 17:13
  • 1
    "I attempted to use some for loops nested together, but it got complicated quickly..." -- please share your attempt. Commented Jul 11, 2021 at 17:15
  • Why are the id values repeated in ids? Seems like useless duplication. You can get the keys from an object with Object.keys. Commented Jul 11, 2021 at 17:24
  • Your question is unclear: some ids elements do not exist as a key in obj, and / or, some obj keys do not exist in the ids array? Commented Jul 11, 2021 at 17:58

7 Answers 7

1

In a first step, you obtain a list of unique group names present in the data. Then, you filter out the temperatures for each group and compute the average.

You can also use lodash functions for removing duplicate entries from a list (_.uniq) and to sum an array of numbers (_.sum).

var ids = [46,44,49,47];
var obj = {
        "46": {
            "group": "A",
            "temp": 26,
            "humid": 36
        },
        "44": {
            "group": "B",
            "temp": 19,
            "humid": 32
        },
        "49": {
            "group": "B",
            "temp": 20,
            "humid": 31
        },
        "47": {
            "group": "A",
            "temp": 24,
            "humid": 32
        }
    };
function onlyUnique(value, index, self) {
  return self.indexOf(value) === index;
}

let groups = Object.values(obj).map((o)=>o.group).filter(onlyUnique)
for (let group of groups) {
  let temps = Object.values(obj).filter((o)=>o.group===group).map((o)=>o.temp)
  let avgtmp = temps.reduce((pv, cv) => pv + cv, 0)/temps.length;
  console.log(`group ${group} has an avg tmp of ${avgtmp}`)
}

// OUTPUT
// group B has an avg tmp of 19.5
// group A has an avg tmp of 25
Sign up to request clarification or add additional context in comments.

1 Comment

I didn't downvote, but the solution is not efficient.
1

You can use Object.keys(obj) to get each ids of the group.

Then you can get values from this group like this:

const obj = {
        "46": {
            "group": "A",
            "temp": 26,
            "humid": 36
        },
        "44": {
            "group": "B",
            "temp": 19,
            "humid": 32
        },
        "49": {
            "group": "B",
            "temp": 20,
            "humid": 31
        },
        "47": {
            "group": "A",
            "temp": 24,
            "humid": 32
        }
    };

Object.keys(obj).map((id) => console.log(`Temp of id ${id} is ${obj[id].temp}`))

We can create the object with group values.

Now if you can map your obj, let's create the average value of each group.

const obj = {
            "46": {
                "group": "A",
                "temp": 26,
                "humid": 36
            },
            "44": {
                "group": "B",
                "temp": 19,
                "humid": 32
            },
            "49": {
                "group": "B",
                "temp": 20,
                "humid": 31
            },
            "47": {
                "group": "A",
                "temp": 24,
                "humid": 32
            }
        };
const groups = {};

Object.keys(obj).map((id) => {
  if(!!groups[obj[id].group]) {
    groups[obj[id].group].push(obj[id].temp);
  } else {
    groups[obj[id].group] = [obj[id].temp]
  }
})

console.log(groups)

Then finally we can count average temps.

const obj = {
            "46": {
                "group": "A",
                "temp": 26,
                "humid": 36
            },
            "44": {
                "group": "B",
                "temp": 19,
                "humid": 32
            },
            "49": {
                "group": "B",
                "temp": 20,
                "humid": 31
            },
            "47": {
                "group": "A",
                "temp": 24,
                "humid": 32
            }
        };
const groups = {};

Object.keys(obj).forEach((id) => {
  if(!!groups[obj[id].group]) {
    groups[obj[id].group].push(obj[id].temp);
  } else {
    groups[obj[id].group] = [obj[id].temp]
  }
})

function getAvg(grades) {
  const total = grades.reduce((acc, c) => acc + c, 0);
  return total / grades.length;
}

Object.keys(groups).forEach((group) => {
  groups[group] = getAvg(groups[group])
})

console.log(groups)

Comments

1

This should be a little bit shorter:

 let output = {};
 
 for (let group in obj) {
        const groupName = obj[group]['group'];
        if(!output[groupName]) {
            output[groupName] =  obj[group]['temp'];
         } else {
            output[groupName] = (output[groupName] + obj[group]['temp'])/2;
         }
 }
 console.log(output);

1 Comment

You seem to assume there are always 2 entries per group. I wouldn't assume that. What if there are three? Then dividing by 2 is not right...
1

Create the target object first with sums and counts, and then divide those to averages:

function getAvgTemp(obj) {
    let data = Object.values(obj);
    let result = Object.fromEntries(data.map(({group}) => [group, { sum: 0, count: 0 }]));
    for (let {group, temp} of data) {
        let o = result[group];
        o.count++; 
        o.sum += temp;
    }
    for (let key of Object.keys(result)) {
        result[key] = result[key].sum / result[key].count;
    }
    return result;
}

// Demo    
var obj = {"46": {"group": "A","temp": 26,"humid": 36},"44": {"group": "B","temp": 19,"humid": 32},"49": {"group": "B","temp": 20,"humid": 31},"47": {"group": "A","temp": 24,"humid": 32}};
let avgTemp = getAvgTemp(obj);
console.log(avgTemp);

Note that the ids array seems overkill, since the properties of the object can be collected with Object.keys.

Comments

0

One more example in functional style)

function avg(vals: number[]): number {
    return vals.reduce((a, b) => a + b) / vals.length;
}

function groupBy<Item, Desc extends string | number>(descriminator: (item: Item) => Desc) {
    return (items: Item[]): Record<Desc, Item[]> => items.reduce((groups, item) => ({
        ...groups,
        [descriminator(item)]: [...(groups[descriminator(item)] || []), item]
    }), {} as Record<Desc, Item[]>);
}

function mapValues<From, To>(mapper: (from: From) => To) {
    return (record: Record<string, From>): Record<string, To> => Object.assign(
        {} as Record<string, To>,
        ...Object.keys(record).map(key => ({
            [key]: mapper(record[key])
        }))
    )
}

const groups = groupBy(
    ({ group }: Item) => group
)(
    Object.values(obj)
);

const avgTemps = mapValues(
    (groupItems: Item[]) => avg(groupItems.map(({ temp }) => temp))
)(
    groups
);

TS Playground

Comments

0

First of all, I have taken all the unique groups in a set for distinction. Then created an array of objects is manipulated and eventually all the average, count, and the total is assigned in the array of objects. And the expected result is generated.

  var ids = [46, 44, 49, 47];
  var obj = {
    "46": {
      "group": "A",
      "temp": 26,
      "humid": 36
    },
    "44": {
      "group": "B",
      "temp": 19,
      "humid": 32
    },
    "49": {
      "group": "B",
      "temp": 20,
      "humid": 31
    },
    "47": {
      "group": "A",
      "temp": 24,
      "humid": 32
    }
  };
  var groups = new Set()
  Object.keys(obj).forEach(element => {
    groups.add(obj[element].group);
  });
  var tempAvgByGroups = [];
  const avgTemp = {}
  groups.forEach(element => {
    const groupObj = {
      "group": element,
      "average": 0,
      "count": 0,
      "total": 0,
    }
    Object.keys(obj).forEach(item => {
      if (element === obj[item]["group"]) {
        groupObj["count"] = groupObj["count"] + 1;
        groupObj["total"] = groupObj["total"] + obj[item]["temp"]
      }
    });
    groupObj["average"] = groupObj["total"] / groupObj["count"];
    tempAvgByGroups.push(groupObj);
    avgTemp[element] = groupObj["average"]
  });
  console.log(avgTemp);

Comments

0

you can do that:

const
  ids = [46,44,52,49,47]
, obj = 
    { '46': { group: 'A', temp: 26, humid: 36 } 
    , '44': { group: 'B', temp: 19, humid: 32 } 
    , '49': { group: 'B', temp: 20, humid: 31 } 
    , '47': { group: 'A', temp: 24, humid: 32 }
    , '64': { group: 'A', temp: 25, humid: 32 }
    }
, avgTemps =
    ids.reduce((rO,key)=>{if (obj[key]) rO.push(obj[key]);return rO},[])
      .reduce((res,o,_,Oe)=>
      {
      if(!res[o.group])
        {
        let grp = Oe.filter(x=>x.group===o.group)
                    .map(y=>y.temp)
        res[o.group] = grp.reduce((sum,t)=>sum+t,0) / grp.length
        }
      return res
      },{})


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

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.