[英]Group and aggregate an array of javascript objects
我在合理化和聚合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}]
即-我希望按價格對每組商品進行分組,顯示它們的描述和尺寸范圍。
到目前為止,這是我所擁有的,並且似乎正在運行,但是看起來非常麻煩。 如果能稍微合理化代碼而不是使用本機JS,我真的很樂意使用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;
}
這是使用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>
原始的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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.