Syknapse
Syknapse

Reputation: 152

How to group objects in an array based on a common property into an array of arrays

I'm trying to group objects that have the same property together. I'm starting with an array of objects, and I want to end up with an array that contains several arrays each with the objects that share the same property.

Say I have this array of film objects, they all have a year property, and I want to group all the films with the same year property in their own array and finally have all of those arrays in a single array.

// This is the array I've got
const films = [
  {
    name='film 1',
    year='1992'
  },
  {
    name='film 2',
    year='1992'
  },
  {
    name='film 3',
    year='1995'
  },
  {
    name='film 4',
    year='1995'
  },
  {
    name='film 5',
    year='1995'
  },
  {
    name='film 6',
    year='1998'
  },
  {
    name='film 7',
    year='1998'
  },
]

// And this is the array I want to end up with
const filmsSorted = [
  [
    {
      name='film 1',
      year='1992'
    },
    {
      name='film 2',
      year='1992'
    },
  ]
  [
    {
      name='film 3',
      year='1995'
    },
    {
      name='film 4',
      year='1995'
    },
    {
      name='film 5',
      year='1995'
    },
  ]
  [
    {
      name='film 6',
      year='1998'
    },
    {
      name='film 7',
      year='1998'
    },
  ]
]

Bear in mind that I don't have the year property in advance and must deal dynamically with whatever year I receive in the original array.

While there are plenty of questions about sorting and filtering arrays on here, I couldn't find an answer to this specific problem. I tried to use reduce() and filter() and a combination of them, but I just can't seem to get my head around it. I have found some possible solutions (transforming it into an object and back into an array) but what I would really like is to see a few different ways that this might be solved to help me reason about it better.

Upvotes: 1

Views: 1595

Answers (3)

Syknapse
Syknapse

Reputation: 152

I have found another way of doing this, I will leave it here in case it's useful for future readers.

const films = [{ name: 'film 1', year: '1992' }, { name: 'film 2', year: '1992' }, { name: 'film 3', year: '1995' }, { name: 'film 4', year: '1995' }, { name: 'film 5', year: '1995' }, { name: 'film 6', year: '1998' }, { name: 'film 7', year: '1998' }]
let filmsSorted = []
let years = {}

films.forEach(film => {
    if (!years[film.year]) years[film.year] = []
    years[film.year].push(film)
})

filmsSorted = Object.values(years)

This creates an interim object, which has key/value pairs of the common properties (years) and arrays of all the objects containing this property. Then we can simply create an array of the values and we end up with the sorting required.

Upvotes: 0

Lauren Yim
Lauren Yim

Reputation: 14118

Try this:

const films = [
  {
    name: 'film 1',
    year: '1992'
  },
  {
    name: 'film 2',
    year: '1992'
  },
  {
    name: 'film 3',
    year: '1995'
  },
  {
    name: 'film 4',
    year: '1995'
  },
  {
    name: 'film 5',
    year: '1995'
  },
  {
    name: 'film 6',
    year: '1998'
  },
  {
    name: 'film 7',
    year: '1998'
  }
]

const result = films.reduce((acc, curr) => {
  if (acc.some(e => e[0].year === curr.year)) acc.filter(e => e[0].year === curr.year)[0].push(curr)
  else acc.push([curr])
  
  return acc
}, [])

console.log(result)

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386660

Just take a hash table and group by year and take the values from the hash table.

Bonus: A sorted result, because the keys of the object are sorted, if the keys could be read as indices of an array.

var films = [{ name: 'film 1', year: '1992' }, { name: 'film 2', year: '1992' }, { name: 'film 3', year: '1995' }, { name: 'film 4', year: '1995' }, { name: 'film 5', year: '1995' }, { name: 'film 6', year: '1998' }, { name: 'film 7', year: '1998' }],
    grouped = Object.values(
        films.reduce((r, o) => {
            (r[o.year] = r[o.year] || []).push(o);
            return r;
        }, {})
    );

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 4

Related Questions