Search code examples
javascripttypescriptreact-nativereact-native-sectionlist

How to separate an array by a property?


I have an array of products that have 5 properties, one of those being "category". What i want to achieve is to get a new array that separates these products by category BUT with the category in a "title" property, so the final array has the shape of

[{
title: "category1",
data: [{product1,product2,...}]
},{
title: "category2",
data: [{product3,product4,...}]}
]

I found a similar question but that doesnt give me the "title" prop, instead it gives me:

[{
cateogry1: [{product1,product2,...}],
category2: [{product3,product4,...}],
}]

And this doesnt work because im trying to use this array in a SectionList in ReactNative which needs the data to have the other specific shape. If anyones know a way in which I can separate the array like this or use the original array in a SectionList that would be great.


Solution

  • You can use the reduce() method of the Array to "map" your items one after the other

    
    // You can have as many extra attributes as you want inside here. I only put "index"
    const products = [{
        category: 'category1',
        index: '1'
      },
      {
        category: 'category2',
        index: '2'
      },
      {
        category: 'category2',
        index: '3'
      },
      {
        category: 'category1',
        index: '4'
      },
      {
        category: 'category1',
        index: '5'
      },
      {
        category: 'category2',
        index: '6'
      },
    ]
    
    
    // Use a reduce on the existing array. It iterate on the array and provide 
    // an accumulator (here called acc) initialized at the last row as an empty array
    const transformedProducts = products.reduce((acc, product) => {
      // Look for an existing object. Search in the accumulator a title equal to the current iterated product category
      const index = acc.findIndex(group => group.title === product.category)
        
      if(index < 0) {
          // If no existing object is found you create one and put the iterated product in it
          acc.push({ title: product.category, data: [product] })
      } else {
          // If you find it you use it to add the new product to the list
          acc[index].data = [...acc[index].data, product]
      }
        
      return acc
    }, []);