Home > other >  How to grouping array with multiple properties
How to grouping array with multiple properties

Time:01-25

I have a doubt about grouping in Javascript.

I have an array like the one below, where each item is guaranteed to have only one of is_sweet, is_spicy, or is_bitter equal to true:

const foodsData = [{
      name: 'mie aceh',
      is_sweet: false,
      is_spicy: true,
      is_bitter: false,
    }, {
      name: 'nasi padang',
      is_sweet: false,
      is_spicy: true,
      is_bitter: false,
    }, {
      name: 'serabi',
      is_sweet: true,
      is_spicy: false,
      is_bitter: false,
    }, {
      name: 'onde-onde',
      is_sweet: true,
      is_spicy: false,
      is_bitter: false,
    }, {
      name: 'pare',
      is_sweet: false,
      is_spicy: false,
      is_bitter: true,   
}];

The output that I desire is to group an array based on is_sweet for its first element, is_bitter for its second element, and is_spicy for its third_element like the output below:

[ 
  [ 
    { name: 'serabi',
      is_sweet: true,
      is_spicy: false,
      is_bitter: false },
    { name: 'onde-onde',
      is_sweet: true,
      is_spicy: false,
      is_bitter: false } 
  ],
  [ 
    { name: 'pare',
      is_sweet: false,
      is_spicy: false,
      is_bitter: true } 
  ],
  [ 
    { name: 'mie aceh',
      is_sweet: false,
      is_spicy: true,
      is_bitter: false },
    { name: 'nasi padang',
      is_sweet: false,
      is_spicy: true,
      is_bitter: false } 
  ] 
]

I've tried to do this by writing the codes below

const isSweet = foodsData.filter(food => food.is_sweet);
const isBitter = foodsData.filter(food => food.is_bitter);
const isSpicy = foodsData.filter(food => food.is_spicy);
const newFood = [];
newFood.push(isSweet);
newFood.push(isBitter);
newFood.push(isSpicy);

Is there a way to make the same result but with cleaner code either using vanilla Javascript or Lodash?

CodePudding user response:

You've clarified that every item can only have one of the three properites is_sweet/is_spicy/is_bitter equal to true.

Given this assumption, one approach is that we can group the items based on the value of the quantity x.is_sweet*4 x.is_spicy*2 x.is_bitter*1 for the item x. This quantity is equal to 1 for those who have only is_bitter: true, 2 for item having only is_spicy: true, and 4 for item having only is_sweet: true.

Once you group according to that quantity, you can use _.values to get rid of the keys created by _.groupBy:

_.values(_.groupBy(foodsData, x => x.is_sweet*4   x.is_spicy*2   x.is_bitter*1))

Obviously you can give a descriptive name to the predicate:

const flavour = food => food.is_sweet*4   food.is_spicy*2   food.is_bitter*1;
let groupedFoods = _.values(_.groupBy(foodsData, flavour))

Notice that in case items are allowed to have more than one of those three keys true, the code above will still give sensible results, in the sense that you will have the eight groups relative to [is_sweet, is_spicy, is_bitter] equal to [0,0,0], [0,0,1], [0,1,0], [0,1,1], [1,0,0], [1,0,1], [1,1,0], and [1,1,1].

CodePudding user response:

While the other two answers are correct, I personally find this the most readable.

For your example input:

const input = [
  {
    name: "mie aceh",
    is_sweet: false,
    is_spicy: true,
    is_bitter: false,
  },
  ...
];

You can call reduce on the array. Reducing the array, iterates over the items in an array, reducing those values into an accumulator (acc). Your accumulator can be any value, and depends on what you want your output to be. In this case, I think it an object, mapping the name of your groups (isSweet, isSpicy, etc..) to an array works the best.

const { isSweet, isSpicy, isBitter } = input.reduce(
  (acc, item) => {
    if (item.is_sweet) {
      acc.isSweet.push(item);
    } else if (item.is_spicy) {
      acc.isSpicy.push(item);
    } else if (item.is_bitter) {
      acc.isBitter.push(item);
    }
    return acc;
  },
  {
    isSweet: [],
    isSpicy: [],
    isBitter: [],
  }
);

Then you can use the object spread operator to get the groups as variables.

  •  Tags:  
  • Related