0

I have an array of objects and I am trying to group them by similar property value. So lets say here is array

[  
  {  
    "size":"6.5",
    "width":"W"
  },
  {  
    "size":"6.5",
    "width":"M"
  },
  {  
    "size":"7.5",
    "width":"w"
  },
  {  
    "size":"8",
    "width":"M"
  },
  {  
    "size":"8",
    "width":"w"
  }
]

and i am trying to get something like this

[  
  {  
    "size_new":"6.5",
    "width_group":[  
      "W",
      "M"
    ]
  },
  {  
    "size_new":"7.5",
    "width_group":[  
      "M"
    ]
  },
  {  
    "size_new":"8",
    "width_group":[  
      "w",
      "M"
    ]
  }
]

My js looks like this

var _x = [];

for(var i = 0; i < x.length; i++){
    if(x[i].size == x[i+1].size){
        _x[i] = {
            new_size: x[i].size,
            width_group: [x[i].width,x[i+1].width]
        }
    }
}

Here is my fiddle http://jsfiddle.net/sghoush1/ogrqg412/1/

I am pretty sure that there is probably a giant gaping hole in my logic

Xotic750
  • 22,914
  • 8
  • 57
  • 79
soum
  • 1,131
  • 3
  • 20
  • 47
  • possible duplicate of [Remap array to object](http://stackoverflow.com/questions/28182367/remap-array-to-object) – Xotic750 Jan 28 '15 at 00:30
  • 1
    var o={};x.forEach(function(a){o[a.size]=o[a.size]||{size: a.size, widths: []}; o[a.size].widths.push(a.width); });o; – dandavis Jan 28 '15 at 00:34
  • @dandavis That doesn't produce the same output as requested. http://jsfiddle.net/uua3cyf1/ – Xotic750 Jan 28 '15 at 00:56
  • Use lodash groupBy function – makeitmorehuman Jan 28 '15 at 01:28
  • 1
    One problem with your code is `x[i].size == x[i+1].size`, when `i` is the index of the last item then item `i + 1` doesn't exist and hence your code gives `Uncaught TypeError: Cannot read property 'size' of undefined ` – Xotic750 Jan 28 '15 at 01:40

2 Answers2

3

One simple way to do this would be to break this into several steps:

var sizeSorter = function(a, b) {return a - b};
var sizes = data.reduce(function(acc, item) {
    (acc[item.size] || (acc[item.size] = [])).push(item.width);
    return acc;
}, {}); //=> {8: ['M', 'W'], '6.5': ['W', 'M'], '7.5': ['W']}
Object.keys(sizes).sort(sizeSorter).map(function(size) {
    return {size_new: size, width_group: sizes[size]};
});

That sorting is necessary because the keys will be sorted in Array order, with small numbers like '8' before strings like '6.5'.

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
1

You need to search if you have already added a specific size and then update only its width. Otherwise insert a new object

var _x = x.reduce(function(p,v){
    var existing = p.filter(function(item){return item.new_size === v.size})[0];
    if (existing){
        existing.width_group.push( v.width );
    } else {
        p.push( {
            new_size: v.size,
            width_group:[v.width]
        } );
    }
    return p;
},[]);

Demo at http://jsfiddle.net/ogrqg412/3/

Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317