0

Here's my array:

const array = [
    {
        name: "kano",
        subject: "gujarati",
        marks: 99
    },
    {
        name: "kano",
        subject: "maths",
        marks: 99
    },
    {
        name: "kano",
        subject: "hindi",
        marks: 99
    },
    {
        name: "dixit",
        subject: "hindi",
        marks: 80
    },
    {
        name: "dixit",
        subject: "maths",
        marks: 80
    },
    {
        name: "dixit",
        subject: "gujarati",
        marks: 80
    },
]

How can I group it by name so that I would get the result of:

 {
    kano: {
        gujarati: 99,
        maths: 99,
        hindi: 99,
        total: 297,
        percentage: 99
    },
    dixit: {
        gujarati: 80,
        maths: 80,
        hindi: 80,
        total: 240,
        percentage: 80
    }

}
Filburt
  • 17,626
  • 12
  • 64
  • 115
  • 1
    Hi! Welcome to StackOverflow! Please take a look at our [tour] to get a better understanding about how to [ask a good question](https://stackoverflow.com/help/how-to-ask). Afterwards, please [edit] your question to add *all* the relevant code. – 0stone0 Mar 01 '23 at 15:24
  • 1
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/group – mwl Mar 01 '23 at 15:29
  • Does this answer your question? [How can I group an array of objects by key?](https://stackoverflow.com/questions/40774697/how-can-i-group-an-array-of-objects-by-key) – 0stone0 Mar 01 '23 at 16:00

5 Answers5

0

You can use reduce method to group values.

let output = array.reduce((acc, item) => {
  if (!acc[item.name]) {
    acc[item.name] = { [item.subject]: item.marks };
  } else {
    acc[item.name][item.subject] = item.marks;
  }
  
  return acc;
}, {});

output = Object.entries(output).reduce((acc, [key, value]) => {
  const total = Object.values(value).reduce((total, curr) => total + curr, 0);
  const percentage = total / Object.values(value).length;
  acc[key] = { ...value, total, percentage };
  return acc;
}, {});


console.log(output)
Mereke
  • 99
  • 8
0

Use reduce() were you

  • Create the object with total and percentage if it doesn't exist
  • Add c.marks to c.subject
  • Add c.marks to total
  • Overwrite percentage if c.marks is larger, otherwise, just keep it

const array = [{name: "kano", subject: "gujarati", marks: 99 }, {name: "kano", subject: "maths", marks: 99 }, {name: "kano", subject: "hindi", marks: 99 }, {name: "dixit", subject: "hindi", marks: 80 }, {name: "dixit", subject: "maths", marks: 80 }, {name: "dixit", subject: "gujarati", marks: 80 }, ];

const res = array.reduce((p, c) => {
  p[c.name] = (p[c.name] || { total: 0, percentage: 0 });
  p[c.name][c.subject] = (p[c.name][c.subject] || 0) + c.marks;
  p[c.name].total += c.marks;
  p[c.name].percentage = (c.marks > p[c.name].percentage ? c.marks : p[c.name].percentage); 
  
  return p;
}, {});

console.log(res)

Instead of altering p as shown above, we could also instant return an object, were we spread (...) the new data to. Not as readable, but thought I'd share:

.reduce((p, c) => ({
    ...p,
    [c.name]: {
       ...(p[c.name] || { }),
       total: (p[c.name]?.total || 0) + c.marks,
       [c.subject]: (p[c.subject] || 0) + c.marks,
       percentage: (p[c.subject]?.percentage || 0) > c.marks ? p[c.subject].percentage  : c.marks
    }
}), {});

const res = [{name: "kano", subject: "gujarati", marks: 99 }, {name: "kano", subject: "maths", marks: 99 }, {name: "kano", subject: "hindi", marks: 99 }, {name: "dixit", subject: "hindi", marks: 80 }, {name: "dixit", subject: "maths", marks: 80 }, {name: "dixit", subject: "gujarati", marks: 80 } ]

.reduce((p, c) => ({
    ...p,
    [c.name]: {
       ...(p[c.name] || { }),
       total: (p[c.name]?.total || 0) + c.marks,
       [c.subject]: (p[c.subject] || 0) + c.marks,
       percentage: (p[c.subject]?.percentage || 0) > c.marks ? p[c.subject].percentage  : c.marks
    }
}), {});

console.log(res)

Both snippets generate:

{
  "kano": {
    "total": 297,
    "percentage": 99,
    "gujarati": 99,
    "maths": 99,
    "hindi": 99
  },
  "dixit": {
    "total": 240,
    "percentage": 80,
    "hindi": 80,
    "maths": 80,
    "gujarati": 80
  }
}
0stone0
  • 34,288
  • 4
  • 39
  • 64
0

You can define helper functions to create or update a student ( using spread syntax ... to exclude student's name). Next, you can use ternary operator to conditionally assign a value to the student's name key in the forEach loop (uses object destructuring syntax). Update the student if the name exist as the key on students object, otherwise create new student

const array = [
  { name: "kano", subject: "gujarati", marks: 99 },
  { name: "kano", subject: "maths", marks: 99 },
  { name: "kano", subject: "hindi", marks: 99 },
  { name: "dixit", subject: "hindi", marks: 80 },
  { name: "dixit", subject: "maths", marks: 80 },
  { name: "dixit", subject: "gujarati", marks: 80 },
];

const genStudentsStats = (array) => {
  const students = {};
  const create = (name, subject, marks) => ({
    name,
    total: marks,
    percentage: marks / 3,
    [subject]: marks,
  });

  const update = (student, subject, marks) => {
    const {name,...rest } = student;
    return {
      ...rest,
      [subject]: marks,
      total: student.total + marks,
      percentage: (student.total + marks) / 3,
    };
   
  };

  array.forEach(({ name,subject, marks}) => {
    students[name] ?
      (students[name] = update(students[name], subject, marks)) :
      (students[name] = create(name, subject, marks));
  });

  return students;
};


const result = genStudentsStats(array);

console.log(result);
protob
  • 3,317
  • 1
  • 8
  • 19
0

You can try it:

const array = [
    {
        name: "kano",
        subject: "gujarati",
        marks: 99
    },
    {
        name: "kano",
        subject: "maths",
        marks: 99
    },
    {
        name: "kano",
        subject: "hindi",
        marks: 99
    },
    {
        name: "dixit",
        subject: "hindi",
        marks: 80
    },
    {
        name: "dixit",
        subject: "maths",
        marks: 80
    },
    {
        name: "dixit",
        subject: "gujarati",
        marks: 80
    },
];
const sbj = ['gujarati', 'maths', 'hindi'];
const res = array.reduce((acc, {name, subject, marks}) => {
    acc[name] ??= {gujarati: 0, maths: 0, hindi: 0, total: 0, percentage: 0};
    for (let i of sbj) {
        if (subject == i) acc[name][subject] = marks;
    }
    acc[name].total += marks;
    acc[name].percentage = acc[name].total / 3;
    return acc;
}, {});
console.log(res);
Hoang Son
  • 58
  • 6
-1

const array = [
    {
        name: "kano",
        subject: "gujarati",
        marks: 99
    },
    {
        name: "kano",
        subject: "maths",
        marks: 99
    },
    {
        name: "kano",
        subject: "hindi",
        marks: 99
    },
    {
        name: "dixit",
        subject: "hindi",
        marks: 80
    },
    {
        name: "dixit",
        subject: "maths",
        marks: 80
    },
    {
        name: "dixit",
        subject: "gujarati",
        marks: 80
    },
];

let output = {};
for (let item of array) {
    if (!output[item.name]) output[item.name] = { [item.subject]: item.marks};
    else output[item.name][item.subject] = item.marks;
}

for (let key in output) {
    let total = 0;
    let cnt = 0;
    for (let innerKey in output[key]) {
        total += output[key][innerKey];
        cnt++;
    }
    output[key].total = total;
    output[key].precentage = total / cnt;
}

document.write(JSON.stringify(output))
<b>Expected</b>

<br>

<code>
{
    kano: {
        gujarati: 99,
        maths: 99,
        hindi: 99,
        total: 297,
        percentage: 99
    },
    dixit: {
        gujarati: 80,
        maths: 80,
        hindi: 80,
        total: 240,
        percentage: 80
    }

}
</code>

<br>

<b>Actual</b>

<br>

Explanation:

  • we create an empty object
  • we loop our initial array and in each step
    • we create the inner object by name if it did not already exist
    • we add the new key-value pair to the new inner object
  • we loop our result and for each of its items
    • we create a total and a cnt variable initialized with 0
    • we loop the inner objects and
      • add its value to total
      • increment cnt
    • we store total as the inner object's total
    • we compute percentage and store that too
Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175