0

I have the following where I am adding objects into an array based on the catType value.
This works fine. But is there a way I could have written this more elegantly?
Possibly combining the steps plus without having to create empty arrays for the map at the start.

const cats = ['cat1', 'cat2']

let newMap = {};
// initialise map with values from above array as keys and values as empty arrays 
cats.forEach(category => {
    newMap[category.title] = [];
});

// list of objects
const newList = [
    {
        catType: 'cat1',
        name: 'name1'
    },
    {
        catType: 'cat2',
        name: 'name2'
    },
    {
        catType: 'cat1',
        name: 'name3'
    },
    {
        catType: 'cat2',
        name: 'name4'
    },
    {
        catType: 'cat1',
        name: 'name5'
    }
]

// add each object to a list in above map based on the `catType` value
newList.forEach(detail => {
    newMap[detail.catType].push(detail);
});

Expected outcome

{
    cat1: [
        {
            catType: 'cat1',
            name: 'name1'
        },
        {
            catType: 'cat1',
            name: 'name3'
        },
        {
            catType: 'cat1',
            name: 'name5'
        }
    ],
    cat2: [
        {
            catType: 'cat2',
            name: 'name2'
        },
        {
            catType: 'cat2',
            name: 'name4'
        }
    ],
}

To note:

I have looked at another prior question with some answers.
The answers in there is not what I am looking for.
This is to achieve a map where the keys are strings and values are array of objects.
And the data is obtained from 2 lists (newList and cats).
This is the past question for reference.
https://stackoverflow.com/questions/14446511/most-efficient-method-to-groupby-on-an-array-of-objects

Jack Gentry
  • 277
  • 1
  • 2
  • 8
  • Sounds like a job for [`[].reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)! – codeth Feb 17 '21 at 22:59

3 Answers3

0

Simple sort, nothing fancy here.

// list of objects
const newList = [
    {
        catType: 'cat1',
        name: 'name1'
    },
    {
        catType: 'cat2',
        name: 'name2'
    },
    {
        catType: 'cat1',
        name: 'name3'
    },
    {
        catType: 'cat2',
        name: 'name4'
    },
    {
        catType: 'cat1',
        name: 'name5'
    }
]

let cats1 = [];
let cats2 = [];

var sortCats = () => {
  for(let listItem of newList) {
    if (listItem.catType === "cat1") cats1.push(listItem);
    if (listItem.catType === "cat2") cats2.push(listItem)
  }
}

sortCats();

let obj = {
  cat1: cats1,
  cat2: cats2
}


console.log(obj);
MinorFourChord
  • 260
  • 1
  • 4
-1

Since it seems like all cats are mentioned again as catType properties:

newList.reduce((acc, curr) => {
  if (acc.hasOwnProperty(curr.catType)) {
    acc[curr.catType].push(curr);
  } else {
    acc[curr.catType] = [curr];
  }

  return acc;
}, {});

Which, yeah, is just a groupBy. Abstract away the field by which the grouping is supposed to happen and you got yourself a groupBy fn:

let groupBy = (array, field) => {
  return array.reduce((acc, curr) => {
    if (acc.hasOwnProperty(curr[field]) {
      acc[curr[field]].push(curr);
    } else {
      acc[curr[field]] = [curr];
    }

    return acc;
  }, {});
}

groupBy(newList, 'catType');

Bonus points if you do everything without mutation, but that's out of scope for this answer.

Dennis Hackethal
  • 13,662
  • 12
  • 66
  • 115
  • This looks great. Appreciate it. May I ask, something I don't get. What is the reasoning for comma, {} at the end pls? – Jack Gentry Feb 18 '21 at 00:02
  • 1
    It's an optional parameter `reduce` takes so you can set the initial value of `acc`. If it's not passed, `acc` defaults to the first element in the array, and iteration starts not at the first but at the second element. Since you want the result to be a map, we pass an empty map as initial value. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#syntax – Dennis Hackethal Feb 18 '21 at 00:23
-1

here's one way:

const cats = ['cat1', 'cat2']
const newList = [
    { catType: 'cat1', name: 'name1' },
    { catType: 'cat2', name: 'name2' },
    { catType: 'cat1', name: 'name3' },
    { catType: 'cat2', name: 'name4' },
    { catType: 'cat1', name: 'name5' }
]

cats.map(c => {return {[c]: newList.filter(nl => nl['catType'] === c)}})

=> [
    {
      cat1: [
        {catType: "cat1", name: "name1"},
        {catType: "cat1", name: "name3"},
        {catType: "cat1", name: "name5"}
      ]
    },  
    {
      cat2: [
        {catType: "cat2", name: "name2"},
        {catType: "cat2", name: "name4"}
      ]
    }   
]   
Dennis Hackethal
  • 13,662
  • 12
  • 66
  • 115
keithpjolley
  • 2,089
  • 1
  • 17
  • 20