对javascript对象数组进行分组和聚合

对javascript对象数组进行分组和聚合,javascript,arrays,sorting,underscore.js,lodash,Javascript,Arrays,Sorting,Underscore.js,Lodash,我在用javascript合理化和聚合对象数组时遇到了一些问题 给定数组 [{"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.9

我在用javascript合理化和聚合对象数组时遇到了一些问题

给定数组

[{"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}]
我正在尝试将其转换为以下格式的数组(此处的实际值可能错误)

也就是说,我希望按价格对每套商品进行分组,显示它们的说明和尺寸范围

到目前为止,这就是我所拥有的,它似乎正在发挥作用,但它似乎非常麻烦。真的,我非常乐意使用lodash或下划线之类的东西,如果它能帮助代码合理化一点,而不是使用原生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;
}

这是一个使用lodash的版本。。 我认为这看起来更合理

功能计算(数据){
var sizeSort={S':1,'M':2,'L':3,'XL':4,'2XL':5,
'3XL':6,'4XL':7,'5XL':8};
返回链(数据)。
groupBy(“价格”)。
映射(函数(f){
var sizes=\ u0.chain(f).map('size').uniq()。
sortBy(函数(a){return sizeSort[a]}).value();
返回{
价格:头(f)价格,
description:u.chain(f).map('description').uniq().join(',').value(),
大小:size.length==1?u0.first(大小):0.join([0.first(大小),0.last(大小)],'-')
} 
}).
sortBy(['price'])。
value();
}
//将数据放在末尾,这样就不必向下滚动查看代码
var数据=[{“说明”:“明亮”,“大小”:“2XL”,“价格”:10.99},{“说明”:“明亮”,“大小”:“XL”,“价格”:10.99},{“说明”:“明亮”,“大小”:“L”,“价格”:9.99},{“组”:“Foos”,“说明”:“呆滞”,“大小”:“XL”,“价格”:9.99},{“说明”:“呆滞”,“大小”:“8.99},{“说明”:“呆滞”,“大小”:“2XL”,“价格”:9.99},{“说明”:“闪亮”,“尺寸”:“XL”,“价格”:9.99},{“说明”:“闪亮”,“尺寸”:“S”,“价格”:8.99},{“说明”:“闪亮”,“尺寸”:“3XL”,“价格”:10.3},{“说明”:“闪亮”,“尺寸”:“2XL”,“价格”:9.99}];
console.log(计算(数据));

一个普通的JavaScript解决方案(带有ES6模板字符串)

/*
一些样板函数。列出了下划线/lodash函数
可以在上面替换它们
*/
//.mapObject(对象、减速器)
函数reduceValue(对象,reducer){
让newObject={}
for(对象中的var属性){
if(object.hasOwnProperty(property)){
newObject[property]=减速机(对象[property])
}
}
返回新对象
}
//_uu.groupBy
功能分组依据(arr,键){
让减速机=(分组,项目)=>{
让组值=项[键]
如果(!分组[组值]){
分组[组值]=[]
}
已分组[组值].推送(项目)
返回分组
}
返回arr.reduce(reducer,{})
}
//(二)价值观
函数objectValues(对象){
让值=[]
for(对象中的var属性){
if(object.hasOwnProperty(property)){
push(对象[属性])
}
}
返回值
}
/*
特定功能和数据
*/
//将衬衫映射到他们的订单。
设sizesToNumbers={S':1,'M':2,'L':3,'XL':4,'2XL':5,'3XL':6,'4XL':7,'5XL':8};
//使用数据而不是字符串创建中间摘要。
//这使得处理过程更易于编写和推理
功能还原HirtsToSummary(衬衫){
let reducer=(摘要,衬衫)=>{
摘要['description']。添加(衬衫['description'])
let shirtSize=衬衫['size']
如果(!summary['smallestSize']| | sizesToNumbers[shirtSize]sizesToNumbers[summary['largestSize']]){
摘要['largestSize']=衬衫尺码
}
汇总['price']。推送(衬衫['price'])
返回摘要
}
return shirts.reduce(reducer,{'descriptions':new Set(),'prices':[]})
}
//使用示例中的字符串将衬衫摘要数据转换为“labelized”版本
功能标签shirtSummary(shirtSummary){
设labelizedShirtSummary={}
LabelizedShirtsmary['descriptions']=Array.from(Shirtsmary['descriptions'])。加入(','))
labelizedShirtSummary['price']=shirtSummary['prices'][0]
labelizedShirtSummary['sizes']=`${shirtSummary['smallestSize']}-${shirtSummary['largestSize']}`
返回标签Hirtsummary
}
let group=groupBy(衬衫,“价格”)
let GroupedAndSummary=ReduceValue(分组,reduceShirtsToSummary)
让labelizedSummaries=objectValues(GroupedAndSummaried).map(labelizeShirtSummary)
//提供所需的输出
console.log(labelizedSummaries)

谢谢,FWIW这不是一个家庭作业问题-但如果是,问题会是什么?这里对这些事情进行了一些很好的讨论抱歉,刚刚结束了漫长的一天。编辑以删除“似乎是一个家庭作业问题”的评论。谢谢,这太棒了,lodash链功能只是一张罚单,它确实让代码更加清晰。
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;
}
/*
  Some boilerplate functions. Listed underscore/lodash functions that 
  could replace them above
*/

// _.mapObject(object, reducer)
function reduceValues(object, reducer) {
  let newObject = {}
    for (var property in object) {
      if (object.hasOwnProperty(property)) {
          newObject[property] = reducer(object[property])
      }
    }
  return newObject
}

// _.groupBy
function groupBy(arr, key) {
  let reducer = (grouped, item) => {
    let group_value = item[key]
    if (!grouped[group_value]) {
      grouped[group_value] = []
    }
    grouped[group_value].push(item)
    return grouped
  }
  return arr.reduce(reducer, {})
}

// _.values
function objectValues(object) {
  let values = []
  for (var property in object) {
    if (object.hasOwnProperty(property)) {
        values.push(object[property])
    }
  }
  return values
}

/*
  Shirt specific functions and data
*/

// Mapping of shirts to their order.
let sizesToNumbers = {'S':1, 'M':2, 'L':3, 'XL':4, '2XL':5, '3XL':6, '4XL':7, '5XL':8};

// Create an intermediate summary with data instead of strings.
// This makes processing easier to write and reason about
function reduceShirtsToSummary(shirts) {
  let reducer = (summary, shirt) => {
    summary['descriptions'].add(shirt['description'])
    let shirtSize = shirt['size']
    if (!summary['smallestSize'] || sizesToNumbers[shirtSize] < sizesToNumbers[summary['smallestSize']]) {
      summary['smallestSize'] = shirtSize
    }
    if (!summary['largestSize'] || sizesToNumbers[shirtSize] > sizesToNumbers[summary['largestSize']]) {
      summary['largestSize'] = shirtSize
    }
    summary['prices'].push(shirt['price'])
    return summary
  }
  return shirts.reduce(reducer, {'descriptions': new Set(), 'prices': []})
}

// Convert the shirt summary data into the "labelized" version with strings in the example
function labelizeShirtSummary(shirtSummary) {
  let labelizedShirtSummary = {}
  labelizedShirtSummary['descriptions'] = Array.from(shirtSummary['descriptions']).join(', ')
  labelizedShirtSummary['price'] = shirtSummary['prices'][0]
  labelizedShirtSummary['sizes'] = `${shirtSummary['smallestSize']} - ${shirtSummary['largestSize']}`
  return labelizedShirtSummary
}

let grouped = groupBy(shirts, 'price')
let groupedAndSummarized = reduceValues(grouped, reduceShirtsToSummary)
let labelizedSummaries = objectValues(groupedAndSummarized).map(labelizeShirtSummary)
// Gives desired output
console.log(labelizedSummaries)