I am having some trouble rationalising and aggregating an array of objects in javascript.
Given the array
[{"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}]
I am trying to convert it to an array in the format (actual values may be wrong here).
[{"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}]
That is - I wish to group each set of items by price, showing the descriptions and size ranges for them.
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.
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;
}