最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

how to group by an array in JavaScriptJquery - Stack Overflow

programmeradmin13浏览0评论

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.

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.

Share Improve this question asked Feb 24, 2019 at 21:49 DevTNDevTN 5932 gold badges13 silver badges37 bronze badges 3
  • 2 A Map is not an Array – guest271314 Commented Feb 24, 2019 at 21:54
  • Your function is too basic for what you're expecting I guess. You don't show how you expect to aggregate the month values. You also return the data mapped by location but you're expecting a simple array. – ChiefTwoPencils Commented Feb 24, 2019 at 21:54
  • Order cannot be guaranteed in an object. – Obsidian Age Commented Feb 24, 2019 at 21:55
Add a comment  | 

6 Answers 6

Reset to default 3

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

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

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

One approach is to use .filter() and .map()

var 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 groupBy = (arr, prop, propName1, propName2, propName3) => 
  Object.assign({[prop]:propName1}
  , ...arr.filter(({[prop]:p}) => p === propName1)
    .map(({[propName2]:m, [propName3]:p}) => ({[m]: p}))
  );

const locations = ["CENTRAL", "NORTH"];

let res = locations.map(prop => groupBy(array1, "location", prop, "month", "percentage"));

console.log(res);

The problem is, you can't just rearrange the properties in an object. According to the ECMAScript specifications:

An ECMAScript object is an unordered collection of properties

You can rearrange the properties using your function, but the order will not be guaranteed in the final object.

Here is another example using reduce, pass the callback function and specify the key in it

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
  }
];


function groupBy(list, callback) {
  return list.reduce((acc, x) => {
    const key = callback(x);
    if (!acc[key]) {
      return {
        ...acc,
        [key]: [x]
      }
    }
    return {
      ...acc,
      [key]: [...acc[key], x]
    }

  }, {})
}

// callback function
function locationName(obj) {
  return obj.location
}


console.log('group by location name:', groupBy(array1, locationName));

发布评论

评论列表(0)

  1. 暂无评论