[
{
"airbill_pieces": 1,
"airbillnbr": 81061140,
"load_point": "IND",
"manifestnbr": 1907521,
"handled_pieces": 5,
"manifest_weight": 12548,
},
{
"airbill_pieces": 2,
"airbillnbr": 81061158,
"load_point": "IND",
"manifestnbr": 1907522,
"handled_pieces": 12,
"manifest_weight": 12368,
}
]
required response as
{
"data": {
"load_point": "IND",
"airbill_pieces": "sum of all "handled_pieces" / sum of all "airbill_pieces",
"manifest_weight": sum of "manifest_weight",
"manifestnbr": 1907521,
},
"children": [
{
"data": {
"airbillnbr": 81061140,
"manifest_weight": 12548,
"manifestnbr": 1907521,
"airbill_pieces": 1,
}
},
{
"data": {
"airbillnbr": 81061158,
"manifest_weight": 12368,
"manifestnbr": 1907522,
"airbill_pieces": 2
}
}
]
}
I am using the below code to get the desire output but fail to get exact format. it groups the load_point as a keypair values but i need a object followed by "data" key.
let result = _.chain(outboundAirbills)
.groupBy("load_point")
.pairs()
.map( (currentItem) => {
return _.object(_.zip(["data", "children"], currentItem));
})
.value();
console.log(result);
Any help will be appreciated.
CodePudding user response:
Here is a version in vanilla JS, using two simple helpers, sum
which calculates the sum of an array of numbers, and group
which groups items of an array into subarrays for which the supplied function returns the same value. (It's like lodash's or groupBy
followed by values
, but curried, more like Ramda):
const sum = (ns) => ns .reduce ((a, b) => a b, 0)
const group = (fn) => (xs) => Object .values (
xs .reduce ((a, x) => ((a [fn (x)] = (a [fn (x)] || []) .concat (x)), a), {})
)
const restructure = (xs) =>
group (x => x .load_point) (xs) .map (g => ({
data: {
load_point: g [0] .load_point,
airbill_pieces: sum (g .map (x => x .handled_pieces))
/ sum (g .map (x => x .airbill_pieces)),
manifest_weight:sum (g .map (x => x .manifest_weight)),
// manifestnbr: g [0] .manifestnbr,
},
children: g .map (({load_point, manifest_weight, manifestnbr, airbill_pieces}) =>
({data: {load_point, manifest_weight, manifestnbr, airbill_pieces}})
)
}))
const data = [{airbill_pieces: 1, airbillnbr: 81061140, load_point: "IND", manifestnbr: 1907521, handled_pieces: 5, manifest_weight: 12548, }, {airbill_pieces: 2, airbillnbr: 81061158, load_point: "IND", manifestnbr: 1907522, handled_pieces: 12, manifest_weight: 12368}]
console .log (restructure (data))
.as-console-wrapper {max-height: 100% !important; top: 0}
We first group the data based on load_point
and then, for each group, summarize the result in data
and collect a subset of the fields inside elements of a children
array.
If you do want the first manifestnbr
, just uncomment the relevant line. But it's redundant data since you have it in the first child, and it's incomplete data, since it ignores all the values after the first one; still, it might be necessary for your needs.
You could definitely write this with lodash's groupBy
, but this shows how easy it is to maintain your own collection of tools. (I'm a primary author of another collection of tools, Ramda.) Note that if you wanted to have both groupBy
(which returns an object keyed off the results of the function) and group
, which just groups the array into subarrays), you could build group
atop groupBy
trivially like this:
const groupBy = (fn) => (xs) =>
xs .reduce ((a, x) => ((a [fn (x)] = (a [fn (x)] || []) .concat (x)), a), {})
const group = (fn) => (xs) =>
Object .values (groupBy (fn) (xs))