分组并聚合一个javascript对象数组

时间:2016-10-06 00:17:41

标签: 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.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}]

我正在尝试将其转换为格式的数组(此处的实际值可能有误)。

[{"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}]

那就是 - 我希望按价格对每组项目进行分组,显示它们的描述和大小范围。

到目前为止,这就是我所拥有的,它似乎正在发挥作用,但它似乎非常麻烦。真的,我非常乐意使用像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;
}

2 个答案:

答案 0 :(得分:1)

这是使用lodash的版本.. 我认为它看起来更合理..



function calc(data) {
  var sizeSort = {'S':1, 'M':2, 'L':3, 'XL':4, '2XL':5, 
                  '3XL':6, '4XL':7, '5XL':8};
  return _.chain(data).
  groupBy('price').
  map(function(f){ 
     var sizes = _.chain(f).map('size').uniq().
        sortBy(function (a) { return sizeSort[a] }).value();
     return { 
       price: _.head(f).price,
       description: _.chain(f).map('description').uniq().join(',').value(),
       size: sizes.length === 1 ? _.first(sizes) : _.join([_.first(sizes),_.last(sizes)], ' - ')
     } 
  }).
  sortBy(['price']). 
  value();
}

//put data at end, so not having to scroll down to see code
var data = [{"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}];

console.log(calc(data));

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.3/lodash.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

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

/*
  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)
相关问题