Skip to content

Instantly share code, notes, and snippets.

@mikaello
Forked from JamieMason/group-objects-by-property.md
Last active October 26, 2025 18:51
Show Gist options
  • Select an option

  • Save mikaello/06a76bca33e5d79cdd80c162d7774e9c to your computer and use it in GitHub Desktop.

Select an option

Save mikaello/06a76bca33e5d79cdd80c162d7774e9c 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 keys

This fork of JamieMason's implementation changes the key parameter to be an array of keys instead of just a single key. This makes it possible to group by multiple properties instead of just one.

Implementation

const groupBy = keys => array =>
  array.reduce((objectsByKeyValue, obj) => {
    const value = keys.map(key => obj[key]).join('-');
    objectsByKeyValue[value] = (objectsByKeyValue[value] || []).concat(obj);
    return objectsByKeyValue;
  }, {});
Click to see TypeScript version
/**
 * Group array of objects by given keys
 * @param keys keys to be grouped by
 * @param array objects to be grouped
 * @returns an object with objects in `array` grouped by `keys`
 * @see <https://gist.github.com/mikaello/06a76bca33e5d79cdd80c162d7774e9c>
 */
const groupBy = <T>(keys: (keyof T)[]) => (array: T[]): Record<string, T[]> =>
  array.reduce((objectsByKeyValue, obj) => {
    const value = keys.map((key) => obj[key]).join('-');
    objectsByKeyValue[value] = (objectsByKeyValue[value] || []).concat(obj);
    return objectsByKeyValue;
  }, {} as Record<string, T[]>);

Usage

const cars = [
  { brand: 'Audi', produced: '2016', color: 'black' },
  { brand: 'Audi', produced: '2017', color: 'white' },
  { brand: 'Ford', produced: '2016', color: 'red' },
  { brand: 'Ford', produced: '2016', color: 'white' },
  { brand: 'Peugot', produced: '2018', color: 'white' }
];

const groupByBrand = groupBy(['brand']);
const groupByColor = groupBy(['color']);
const groupByBrandAndYear = groupBy(['brand', 'produced']);

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

Output

{
  "carsByBrand": {
    "Audi": [
      {
        "brand": "Audi",
        "produced": "2016",
        "color": "black"
      },
      {
        "brand": "Audi",
        "produced": "2017",
        "color": "white"
      }
    ],
    "Ford": [
      {
        "brand": "Ford",
        "produced": "2016",
        "color": "red"
      },
      {
        "brand": "Ford",
        "produced": "2016",
        "color": "white"
      }
    ],
    "Peugot": [
      {
        "brand": "Peugot",
        "produced": "2018",
        "color": "white"
      }
    ]
  },
  "carsByColor": {
    "black": [
      {
        "brand": "Audi",
        "produced": "2016",
        "color": "black"
      }
    ],
    "white": [
      {
        "brand": "Audi",
        "produced": "2017",
        "color": "white"
      },
      {
        "brand": "Ford",
        "produced": "2016",
        "color": "white"
      },
      {
        "brand": "Peugot",
        "produced": "2018",
        "color": "white"
      }
    ],
    "red": [
      {
        "brand": "Ford",
        "produced": "2016",
        "color": "red"
      }
    ]
  },
  "carsByBrandAndYear": {
    "Audi-2016": [
      {
        "brand": "Audi",
        "produced": "2016",
        "color": "black"
      }
    ],
    "Audi-2017": [
      {
        "brand": "Audi",
        "produced": "2017",
        "color": "white"
      }
    ],
    "Ford-2016": [
      {
        "brand": "Ford",
        "produced": "2016",
        "color": "red"
      },
      {
        "brand": "Ford",
        "produced": "2016",
        "color": "white"
      }
    ],
    "Peugot-2018": [
      {
        "brand": "Peugot",
        "produced": "2018",
        "color": "white"
      }
    ]
  }
}

See playcode.io for example.

@maciel-82

maciel-82 commented Oct 5, 2021

Copy link
Copy Markdown

is there any way to get the count which group have

Yes, that is possible. The values of a group is just an array, so you could just check the length property of that array:

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

const cars = [
  { brand: "Audi", produced: "2016", color: "black" },
  { brand: "Audi", produced: "2017", color: "white" },
  { brand: "Ford", produced: "2016", color: "red" },
  { brand: "Ford", produced: "2016", color: "white" },
  { brand: "Peugot", produced: "2018", color: "white" },
];

const groupByBrandAndYear = groupBy(["brand", "produced"]);

for (let [groupName, values] of Object.entries(groupByBrandAndYear(cars))) {
  console.log(`${groupName}: ${values.length}`);
}
# console output
Audi-2016: 1
Audi-2017: 1
Ford-2016: 2
Peugot-2018: 1

@mikaello nice work!
BTW is it possible to keep the brand and produced attributes separated in the result, instead of concatenating them?

like this:
{brand: "Audi", produced: 2016, count: 1}
{brand: "Ford", produced: 2016, count: 2}
... and so on.

Thanks

@mikaello

mikaello commented Oct 6, 2021

Copy link
Copy Markdown
Author

@maciel-82 , sure that is possible. But it may be easier to just modify the result accordingly, e.g.

const brandYearCount = Object
  .entries(groupByBrandAndYear(cars))
  .map(([, value]) =>
    ({
      brand: value[0].brand,
      produced: value[0].produced,
      count: value.length
    }))

console.log(brandYearCount)
# Output
[
 {  brand: "Audi",  count: 1,  produced: "2016"},
 {  brand: "Audi",  count: 1,  produced: "2017"},
 {  brand: "Ford",  count: 2,  produced: "2016"},
 {  brand: "Peugot",  count: 1,  produced: "2018"}
]

See JsFiddle

@maciel-82

Copy link
Copy Markdown

@maciel-82 , sure that is possible. But it may be easier to just modify the result accordingly, e.g.

const brandYearCount = Object
  .entries(groupByBrandAndYear(cars))
  .map(([, value]) =>
    ({
      brand: value[0].brand,
      produced: value[0].produced,
      count: value.length
    }))

console.log(brandYearCount)
# Output
[
 {  brand: "Audi",  count: 1,  produced: "2016"},
 {  brand: "Audi",  count: 1,  produced: "2017"},
 {  brand: "Ford",  count: 2,  produced: "2016"},
 {  brand: "Peugot",  count: 1,  produced: "2018"}
]

See JsFiddle

@mikaello it worked perfectly!!!
Thanks a lot!

@Taspee

Taspee commented Nov 15, 2022

Copy link
Copy Markdown

@maciel-82 , sure that is possible. But it may be easier to just modify the result accordingly, e.g.

const brandYearCount = Object
  .entries(groupByBrandAndYear(cars))
  .map(([, value]) =>
    ({
      brand: value[0].brand,
      produced: value[0].produced,
      count: value.length
    }))

console.log(brandYearCount)
# Output
[
 {  brand: "Audi",  count: 1,  produced: "2016"},
 {  brand: "Audi",  count: 1,  produced: "2017"},
 {  brand: "Ford",  count: 2,  produced: "2016"},
 {  brand: "Peugot",  count: 1,  produced: "2018"}
]

See JsFiddle

@mikaello, In this case, how could i get the brand that was produce the most per year?

@aacassandra

Copy link
Copy Markdown

thanks, its great

@reddo

reddo commented Sep 5, 2023

Copy link
Copy Markdown
const groupBy = (keys) => (array) =>
  array.reduce((objectsByKeyValue, obj) => {
   // Instead of creating a unique key for each grouped by values, we are now traversing (and building) 
   // the whole object structure for every array value:
    keys.reduce((builder, key, index) => {
      if (index !== keys.length - 1) {
        // Building the nested grouped by structure
        builder[obj[key]] = builder[obj[key]] || {};
      } else {
        // Appending the current object at the leaf node
        builder[obj[key]] = (builder[obj[key]] || []).concat(obj);
      }
      return builder[obj[key]];
    }, objectsByKeyValue);

    return objectsByKeyValue;
  }, {});

I know this is an old gist, but Is there any way you could help me with the typescript version of this?

@kkg0

kkg0 commented Dec 9, 2023

Copy link
Copy Markdown

how can i iterate through returned array ?

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