我在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;
}
答案 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;
答案 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)