-1

For example, I have list of product objects:

I don't want to to leave only unique objects, but group them into one

    [
            {
                name: "some product",
                type: "other",
                options: [
                    {
                        label: "price",
                        value: 10
                    }
                ]
            },
            {
                name: "merge product",
                type: "merge",
                options: [
                    {
                        label: "size",
                        value: "L"
                    },
                    {
                        label: "color",
                        value: "white"
                    },
                ]
            },
            {
                name: "merge product",
                type: "merge",
                options: [
                    {
                        label: "size",
                        value: "XL"
                    },
                    {
                        label: "color",
                        value: "red"
                    },
                ]
            },
        ]

what I want to get in result, is:

    [
            {
                name: "some product",
                type: "other",
                options: [
                    {
                        label: "price",
                        value: 10
                    }
                ]
            },
            {
                name: "merge product",
                type: "merge",
                options: [
                    {
                        label: "size",
                        value: "L"
                    },
                    {
                        label: "color",
                        value: "white"
                    },
                    {
                        label: "size",
                        value: "XL"
                    },
                    {
                        label: "color",
                        value: "red"
                    },
                ]
            }
    }

Where "merge product" should have options of all objects same name and type "merge". I used to achieve this by for and simple iterations with intermediate list as storage and comparison, but is there any other nice functional way for getting this done?

Ilja
  • 1,205
  • 1
  • 16
  • 33
  • [`Array.prototype.reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) – Andreas Jul 29 '17 at 15:29
  • Possible duplicate of [How to merge two arrays in Javascript and de-duplicate items](https://stackoverflow.com/questions/1584370/how-to-merge-two-arrays-in-javascript-and-de-duplicate-items) – Ali Adlavaran Jul 29 '17 at 15:31

2 Answers2

1

How about extending an array with prototype for group by?

Array.prototype.groupBy = function(prop) {
  return this.slice().reduce(function(groups, item) {
    var val = item[prop];
    groups[val] = groups[val] || [];
    groups[val].push(item);
    return groups;
  }, {});
}

Using it is simple var groupedArray = originalArray.groupBy('name');

Expected result -

{
   "some product":[
      {
         "name":"some product",
         "type":"other",
         "options":[
            {
               "label":"price",
               "value":10
            }
         ]
      }
   ],
   "merge product":[
      {
         "name":"merge product",
         "type":"merge",
         "options":[
            {
               "label":"size",
               "value":"L"
            },
            {
               "label":"color",
               "value":"white"
            }
         ]
      },
      {
         "name":"merge product",
         "type":"merge",
         "options":[
            {
               "label":"size",
               "value":"XL"
            },
            {
               "label":"color",
               "value":"red"
            }
         ]
      }
   ]
}

working demo - https://jsfiddle.net/rahulrulez/0537xesp/

Edit - Updated code with prevention of mutation of original array.

Rahul Patil
  • 5,656
  • 6
  • 37
  • 65
0

Try this:

const mergedArr = myArr.reduce((acc, val) => {
    const prevIndex = acc.findIndex(prevVal => prevVal.name === val.name && prevVal.type === val.type)

  if (prevIndex > -1) {
    acc[prevIndex] = Object.assign(acc[prevIndex], {
      options: acc[prevIndex].options.concat(val.options)
    })
  } else acc.push(val)

  return acc
}, [])
Sam A. Horvath-Hunt
  • 931
  • 1
  • 7
  • 20