Skip to content

Instantly share code, notes, and snippets.

@JamieMason
Created September 14, 2018 07:38
Show Gist options
  • Select an option

  • Save JamieMason/0566f8412af9fe6a1d470aa1e089a752 to your computer and use it in GitHub Desktop.

Select an option

Save JamieMason/0566f8412af9fe6a1d470aa1e089a752 to your computer and use it in GitHub Desktop.
Group Array of JavaScript Objects by Key or Property Value

Group Array of JavaScript Objects by Key or Property Value

Implementation

const groupBy = key => array =>
  array.reduce((objectsByKeyValue, obj) => {
    const value = obj[key];
    objectsByKeyValue[value] = (objectsByKeyValue[value] || []).concat(obj);
    return objectsByKeyValue;
  }, {});

Or using an implicit return (slower):

const groupBy = key => array =>
  array.reduce(
    (objectsByKeyValue, obj) => ({
      ...objectsByKeyValue,
      [obj[key]]: (objectsByKeyValue[obj[key]] || []).concat(obj)
    }),
    {}
  );

Usage

const cars = [
  { brand: 'Audi', color: 'black' },
  { brand: 'Audi', color: 'white' },
  { brand: 'Ferarri', color: 'red' },
  { brand: 'Ford', color: 'white' },
  { brand: 'Peugot', color: 'white' }
];

const groupByBrand = groupBy('brand');
const groupByColor = groupBy('color');

console.log(
  JSON.stringify({
    carsByBrand: groupByBrand(cars),
    carsByColor: groupByColor(cars)
  }, null, 2)
);

Output

{
  "carsByBrand": {
    "Audi": [
      {
        "brand": "Audi",
        "color": "black"
      },
      {
        "brand": "Audi",
        "color": "white"
      }
    ],
    "Ferarri": [
      {
        "brand": "Ferarri",
        "color": "red"
      }
    ],
    "Ford": [
      {
        "brand": "Ford",
        "color": "white"
      }
    ],
    "Peugot": [
      {
        "brand": "Peugot",
        "color": "white"
      }
    ]
  },
  "carsByColor": {
    "black": [
      {
        "brand": "Audi",
        "color": "black"
      }
    ],
    "white": [
      {
        "brand": "Audi",
        "color": "white"
      },
      {
        "brand": "Ford",
        "color": "white"
      },
      {
        "brand": "Peugot",
        "color": "white"
      }
    ],
    "red": [
      {
        "brand": "Ferarri",
        "color": "red"
      }
    ]
  }
}
@humeyra92

Copy link
Copy Markdown

nice!

@r-souza

r-souza commented Apr 5, 2021

Copy link
Copy Markdown

Nice!!!

@VictorLM

Copy link
Copy Markdown

Save my day. Thanks.

@viniciuSquare

Copy link
Copy Markdown

Thanks for that solution, saved me a lot o time.

@hussainahmad

Copy link
Copy Markdown

@JamieMason Thanks for the great code but if we want to get like this

group data = [{"title":"AB", data:[{},{},{}]}, {"title":"BC", data:[{},{},{}]}]

@JamieMason

Copy link
Copy Markdown
Author

Sorry @hussainahmad, I don't understand?

@hussainahmad

Copy link
Copy Markdown

@JamieMason I am talking to convert array like this

[
  {
    "title": "Audi",
    "data": [
      {
        "brand": "Audi",
        "color": "black"
      },
      {
        "brand": "Audi",
        "color": "white"
      }
    ]
  },
  {
    "title": "Ferarri",
    "data": [
      {
        "brand": "Ferarri",
        "color": "red"
      }
    ]
  },
  {
    "title": "Ford",
    "data": [
      {
        "brand": "Ford",
        "color": "white"
      }
    ]
  },
  {
    "title": "Peugot",
    "data": [
      {
        "brand": "Peugot",
        "color": "white"
      }
    ]
  }
]

@JamieMason

Copy link
Copy Markdown
Author

You want to convert that into [{"title":"AB", data:[{},{},{}]}, {"title":"BC", data:[{},{},{}]}]? can you give some more context on what you're trying to build? why would you want those empty objects for example?

@hussainahmad

Copy link
Copy Markdown

@JamieMason empty objects was just an example sorry for confusing you. , let assume I have a data

const cars = [
  { brand: 'Audi', color: 'black' },
  { brand: 'Audi', color: 'white' },
  { brand: 'Ferarri', color: 'red' },
  { brand: 'Ford', color: 'white' },
  { brand: 'Peugot', color: 'white' }
];

and I want to convert this array in to this array

[
  {
    "title": "Audi",
    "data": [
      {
        "brand": "Audi",
        "color": "black"
      },
      {
        "brand": "Audi",
        "color": "white"
      }
    ]
  },
  {
    "title": "Ferarri",
    "data": [
      {
        "brand": "Ferarri",
        "color": "red"
      }
    ]
  },
  {
    "title": "Ford",
    "data": [
      {
        "brand": "Ford",
        "color": "white"
      }
    ]
  },
  {
    "title": "Peugot",
    "data": [
      {
        "brand": "Peugot",
        "color": "white"
      }
    ]
  }
]

@JamieMason

Copy link
Copy Markdown
Author

I think this should do it @hussainahmad:

const groupByBrand = groupBy('brand');
const carsByBrand = groupByBrand(cars);
const carBrands = Object.entries(carsByBrand).map(([title, data]) => ({ title, data }));

@hussainahmad

Copy link
Copy Markdown

Really Thanks to you @JamieMason , May God bless you

@JamieMason

Copy link
Copy Markdown
Author

You're welcome

@MadhuriTank

Copy link
Copy Markdown

@JamieMason, Thanks a lot!!! It is very useful !!!!

@scelloo-elegeonyejerome

Copy link
Copy Markdown

@JamieMason Amazing work.. Quick One, how can one get the count of each group?

@JamieMason

Copy link
Copy Markdown
Author

Like this @scelloo-elegeonyejerome:

const groupBy = (key) => (array) =>
  array.reduce((objectsByKeyValue, obj) => {
    const value = obj[key];
    objectsByKeyValue[value] = (objectsByKeyValue[value] || []).concat(obj);
    return objectsByKeyValue;
  }, {});

const cars = [
  { brand: 'Audi', color: 'black' },
  { brand: 'Audi', color: 'white' },
  { brand: 'Ferarri', color: 'red' },
  { brand: 'Ford', color: 'white' },
  { brand: 'Peugot', color: 'white' },
];

const groupByBrand = groupBy('brand');
const carsByBrand = groupByBrand(cars);

Object.entries(carsByBrand).forEach(([brand, cars]) => {
  console.log(`${cars.length} ${brand}`);
});

Outputs

"2 Audi"
"1 Ferarri"
"1 Ford"
"1 Peugot"

@chgad

chgad commented Aug 29, 2022

Copy link
Copy Markdown

@JamieMason arriving late to the party and newbie to JS: Is there a particular reason for double arrow-functions here or can it be rewritten as function with two parameters key, array ?

@JamieMason

Copy link
Copy Markdown
Author

You could do this @chgad, you're right.

- const groupBy = (key) => (array) =>
+ const groupBy = (key, array) =>

The reason for double arrow-functions (a function creator / a function which returns another function) is so we can do things like this:

export const groupByBrand = groupBy('brand');

so users of your module do this:

groupByBrand(cars);

Instead of this:

groupBy('brand', cars);

Broadly speaking it's a matter of style or taste. It comes from a functional programming-like style of writing JS.

Really – the benefits of it aren't obvious or arguably even applicable in this little example, but generating functions can make for really reusable, readable code. You need to be careful though and develop a sense for knowing when doing this would be an upgrade and not a downgrade.

A rule of thumb would be to not do what I'm doing here, unless you're confident in how to generate and compose functions in a functional style.

@aboudrea

aboudrea commented Aug 30, 2023

Copy link
Copy Markdown

I think this should do it @hussainahmad:

const groupByBrand = groupBy('brand');
const carsByBrand = groupByBrand(cars);
const carBrands = Object.entries(carsByBrand).map(([title, data]) => ({ title, data }));

@JamieMason how could I add another value to the top collection, if I had engine as a value in the original array:

{
  "title": "Audi",
  "engine": "V8",
  "data": [
    {
      "brand": "Audi",
      "color": "black"
    },
    {
      "brand": "Audi",
      "color": "white"
    }
  ]
}

@JamieMason

Copy link
Copy Markdown
Author

@aboudrea please add more detail

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment