title: Group and aggregate an array of javascript objects
body: <p>I am having some trouble rationalising and aggregating an array of objects in javascript. </p>
  
  <p>Given the array</p>
  
  <pre><code>[{"description":"Bright","size":"2XL","price":10.99},{"description":"Bright","size":"XL","price":10.99},{"description":"Bright","size":"L","price":9.99},{"group":"Foos","description":"Dull","size":"XL","price":9.99},{"description":"Dull","size":"L","price":8.99},{"description":"Dull","size":"2XL","price":9.99},{"description":"Shiny","size":"XL","price":9.99},{"description":"Shiny","size":"S","price":8.99},{"description":"Shiny","size":"3XL","price":10.3},{"description":"Shiny","size":"2XL","price":9.99}]
  </code></pre>
  
  <p>I am trying to convert it to an array in the format (actual values may be wrong here).</p>
  
  <pre><code>[{"descriptions":"Shiny, Bright, Dull","sizeRange":"S - L","price":8.99},{"descriptions":"Shiny, Bright, Dull","sizes":"XL - 2XL","price":9.99},{"descriptions":"Dark","sizes":"S - 2XL","price":10.99}]
  </code></pre>
  
  <p>That is - I wish to group each set of items by price, showing the descriptions and size ranges for them.</p>
  
  <p>So far this is what I have, and it seems to be working, but it just seems very cumbersome. Really I'd be more than happy to use something like lodash or underscore if it would help to rationalise the code a bit rather than using native JS.</p>
  
  <pre><code>function groupBy (array, key) {
    return array.reduce(function(value, property) {
      (value[property[key]] = value[property[key]] || []).push(property);
      return value;
    }, {});
  };
  
  function unique(array) {
    return Array.from(new Set(array));
  };
  
  function getRanges(data)
  {
      var result = [];
  
      // simple map of sizes from smallest to largest to use for sorting
      var sizeSort = {'S':1, 'M':2, 'L':3, 'XL':4, '2XL':5, '3XL':6, '4XL':7, '5XL':8};
  
      // group the remaining variants by price
      var group = groupBy(data, 'price');
  
      // for each variant price group 
      for(var price in group) {
          var item = {};
          item.price = price;
          // get the range of sizes sorted smallest to largest
          var sizes = unique(group[price].map(function(i) {
              return i.size;
          })).sort(function(a, b) {
              return sizeSort[a] - sizeSort[b];
          });
  
          // Add single size, or first and last size.
          item.sizes = (sizes.length === 1) ?
             sizes.shift() :
             sizes.shift() + ' - ' + sizes.pop();
  
          // Add the descriptions as alphabetically sorted CSV
          item.description = unique(group[price].map(function(i) {
              return i.description;
          })).sort().join(", ");
  
          result.push(item);
      }
  
      return result;
  }
  </code></pre>