Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to group by an array in JavaScript / Jquery

I have an array as below

array1 = [{"month":"January","location":"CENTRAL","percentage":94},
{"month":"February","location":"CENTRAL","percentage":97},
{"month":"March","location":"CENTRAL","percentage":93},
{"month":"January","location":"NORTH","percentage":95},
{"month":"February","location":"NORTH","percentage":91},
{"month":"March","location":"NORTH","percentage":98}];

I want to format my array to look as below

array2= [{
    location: "CENTRAL",
    January: 94,
    February: 97,
    March: 93},
    {
    location: "NORTH",
    January: 95,
    February: 91,
    March: 98}];

I tried to use group by function as below

function groupBy(list, keyGetter) {
    const map = new Map();
    list.forEach((item) => {
        const key = keyGetter(item);
        if (!map.has(key)) {
            map.set(key, [item]);
        } else {
            map.get(key).push(item);
        }
    });
    return map;
}

const grouped = groupBy(array1, arr => arr.location);
console.log(grouped);

but I am not getting the same format. Any suggestions please what I am missing in my idea ? Thank you very much.

like image 692
DevTN Avatar asked Feb 24 '19 21:02

DevTN


3 Answers

You can indeed use a map keyed by location, but then with plain objects as values. The problem in your code is that you push items into an array, and don't turn the month values into properties of a singular object (per location).

So given a map with plain objects, iterate the input and inject the month properties into those plain objects, with corresponding percentage values, and then take the values of that map:

const array1 = [{"month":"January","location":"CENTRAL","percentage":94},{"month":"February","location":"CENTRAL","percentage":97},{"month":"March","location":"CENTRAL","percentage":93},{"month":"January","location":"NORTH","percentage":95},{"month":"February","location":"NORTH","percentage":91},{"month":"March","location":"NORTH","percentage":98}];

const map = new Map(array1.map(({location}) => [location, { location }]));
array1.forEach(o => map.get(o.location)[o.month] = o.percentage);
const result = [...map.values()];

console.log(result);
like image 161
trincot Avatar answered Nov 16 '22 15:11

trincot


You could use a dynamic approach by handing over the group key, the keys for key and value for collecting.

Then add all key/value pairs to the object and later return the values of the map.

function groupBy(list, group, key, value) {
    return Array.from(list
        .reduce((map, object) => map.set(object[group], Object.assign(
            map.get(object[group]) || { [group]: object[group] },
            { [object[key]]: object[value] }
        )), new Map)
        .values()
    );
}

var array = [{ month: "January", location: "CENTRAL", percentage: 94 }, { month: "February", location: "CENTRAL", percentage: 97 }, { month: "March", location: "CENTRAL", percentage: 93 }, { month: "January", location: "NORTH", percentage: 95 }, { month: "February", location: "NORTH", percentage: 91 }, { month: "March", location: "NORTH", percentage: 98 }],
    result = groupBy(array, 'location', 'month', 'percentage');

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
like image 3
Nina Scholz Avatar answered Nov 16 '22 15:11

Nina Scholz


An alternative is using the function reduce to group by location and the function Object.values to extract the grouped objects.

let array1 = [{"month":"January","location":"CENTRAL","percentage":94},{"month":"February","location":"CENTRAL","percentage":97},{"month":"March","location":"CENTRAL","percentage":93},{"month":"January","location":"NORTH","percentage":95},{"month":"February","location":"NORTH","percentage":91},{"month":"March","location":"NORTH","percentage":98}],
    groupBy = (array, keygetter) => {
      return Object.values(array1.reduce((a, {month, percentage, ...rest}) => {
        let key = keygetter(rest);
        (a[key] || (a[key] = {location: key}))[month] = percentage;
        return a;
      }, Object.create(null)));
    },
    result = groupBy(array1, (o) => o.location);
    
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
like image 3
Ele Avatar answered Nov 16 '22 15:11

Ele