Getting multiple percentage from a reduce map of a json data - javascript

I would like to apologize in advance if there's already question like this but I've been searching all day and I really can find anything.
I call an api that returns a response. Then I only get the details/data that I need and currently now have a json file with this sample value:
{
"total": 563,
"shipping_fee": 58,
"e_charges": ???,
"order_items": [
{
"item_id": 6291020872,
"quantity": 1,
"price": 88,
"total": 88
},
{
"item_id": 7755274567,
"quantity": 1,
"price": 150,
"total": 150
},
{
"item_id": 7980571205,
"quantity": 1,
"price": 45,
"total": 45
},
{
"item_id": 12612977930,
"quantity": 1,
"price": 280,
"total": 280
}
]
}, ... {} {} {}....
My problem is that, I need to get the sum of all total in order_items [] then after that, I need to add the shipping_fee and get 2 sets of percentage
10%
8%
Note that, I'm getting the values in run-time.
const resDetails = await request.post(baseURL, {
data: viewData
});
info = await JSON.parse(JSON.stringify(await resDetails.json()));
This is where the json file came from:
orders = await info.data.orders.map((x) => (total: x.order_items.map(y => Number(y.order_price) * y.amount).reduce((total, y) => y+total),
shipping_fee : Number(x.shipping_fee),
e_charges: Number(Number((x.order_items.map(y=> Number(y.order_price) * y.amount).reduce((total, y) => Number(y+total)) + Number(x.shipping_fee)) * 0.1).toFixed()),
order_items: x.order_items.map((y) => ({
item_id : y.item_id,
quantity: y.amount,
price: Number(y.order_price),
total: Number(y.order_price) * y.amount)}))
I was able to get the 10% but my main problem is adding the other 8% without doing mapping, reducing and adding the shipping_fee again.
Number(Number((x.order_items.map(y=> Number(y.order_price) * y.amount).reduce((total, y) => Number(y+total)) + Number(x.shipping_fee)) * 0.1).toFixed())
I'm fairly new to the javascript/typescript world. I hope someone can help me find a more optimized way to achieve what I need. Thank you.
EDIT:
Here's the actual code:

You may please go through the below code. I'm not a big fan of doing map, reduce and calculations in single line because it takes away the readability. So, I broken down the calculations to a number of methods.
At the end, order total is calculated only once and saved the e_charges percentages in 2 different keys e_charges_8 and e_charges_10, which I believe you can modify as per your need.
let orders = [
{
"shipping_fee": 58,
"order_items": [
{
"item_id": 6291020872,
"quantity": 1,
"price": 88
},
{
"item_id": 7755274567,
"quantity": 1,
"price": 150
},
{
"item_id": 7980571205,
"quantity": 1,
"price": 45
},
{
"item_id": 12612977930,
"quantity": 1,
"price": 280
}
]
},
{
"shipping_fee": 58,
"order_items": [
{
"item_id": 6291020872,
"quantity": 1,
"price": 88
},
{
"item_id": 7755274567,
"quantity": 1,
"price": 150
},
{
"item_id": 7980571205,
"quantity": 1,
"price": 45
},
{
"item_id": 12612977930,
"quantity": 1,
"price": 280
}
]
}
]
const getOrderItemTotal = (orderItem) => {
return orderItem.quantity * orderItem.price
}
const getPercentage = (shippingFee, total, percentage) => {
return ((total + shippingFee) * percentage).toFixed()
}
const getOrderItemsTotal = (orderItems) => {
return orderItems.reduce((total, orderItem) => (total + orderItem.total), 0)
}
orders = orders.map(order => {
order.order_items.map(orderItem => {
orderItem.total = getOrderItemTotal(orderItem)
return orderItem
})
order.total = getOrderItemsTotal(order.order_items)
order.e_charges_8 = getPercentage(order.shipping_fee, order.total, 0.1)
order.e_charges_10 = getPercentage(order.shipping_fee, order.total, 0.08)
return order
})
console.log(orders)

Related

How to sort and filter this array of hashes using underscore

I want to use underscore.js in order to take the highest price for each tokenId in the array of hashes below. I would imagine this would require running through the array twice, but perhaps there is a more efficient way. What's the best way to utilize underscore to only grab one hash keyed by tokenId and to select the one with the highest price with the fewest number of iterations through the entire array set?
const data = [
{
"tokenId": 1,
"price": 1.8
},
{
"tokenId": 1,
"price": 2.0
},
{
"tokenId": 1,
"price": 1.9
},
{
"tokenId": 2,
"price": 5.0
},
{
"tokenId": 2,
"price": 1.0
},
{
"tokenId": 3,
"price": 1.9
}
]
// final result should be
// sortedFiltered = [{tokenId: 1, price: 2.0}, {tokenId: 2, price: 5.0}, {tokenId: 3, price: 1.9}]
A reduce can do it in one iteration. Use the accumulator to keep max price values indexed by tokenId.
const data = [
{
"tokenId": 1,
"price": 1.8
},
{
"tokenId": 1,
"price": 2.0
},
{
"tokenId": 1,
"price": 1.9
},
{
"tokenId": 2,
"price": 5.0
},
{
"tokenId": 2,
"price": 1.0
},
{
"tokenId": 3,
"price": 1.9
}
]
// one iteration, with a custom function
const maxes = data.reduce((acc, o) => {
if (acc[o.tokenId] === undefined) acc[o.tokenId] = 0;
if (acc[o.tokenId] < o.price) acc[o.tokenId] = o.price;
return acc;
}, {});
console.log(maxes);

Using Javascript to isolate an object with an property larger than a given quantity, but smaller than the next object in sequence

In my JavaScript, I have an integer that represents an order quantity, and an object of all quantities offered:
{
"1": {
"quantity": 1,
"price": 10
},
"2": {
"quantity": 2,
"price": 20
},
"6": {
"quantity": 6,
"price": 50
},
"12": {
"quantity": 12,
"price": 80
}
}
I need to find the object with a quantity value greater than my order quantity, but smaller than the quantity value of the next object in the sequence.
For example, if my order quantity is 8, I need to isolate:
"6": {
"quantity": 6,
"price": 50
},
So I can get the correct price. I've tried various LoDash methods, but nothing seems to be quite right. Is there a way that I can achieve this?
You could take the keys and reverse the array and find the smaller or equal count.
function find(object, quantity) {
return Object.keys(object).reverse().find(v => v <= quantity);
}
var object = { 1: { quantity: 1, price: 10 }, 2: { quantity: 2, price: 20 }, 6: { quantity: 6, price: 50 }, 12: { quantity: 12, price: 80 } };
console.log(find(object, 8));
Based on your description, I'm assuming what you're trying to do is find the record corresponding to the lowest quantity higher than the input quantity. The example doesn't actually match that description though. If you're looking for the opposite (next largest, smaller than the input) you could flip the two inequalities.
some_prices = {
"1": {
"quantity": 1,
"price": 10
},
"2": {
"quantity": 2,
"price": 20
},
"6": {
"quantity": 6,
"price": 50
},
"12": {
"quantity": 12,
"price": 80
}
}
getNextQuantityPrice = (prices, quantity) => {
const largerQuantities = Object.values(prices)
.filter(value => value.quantity > quantity);
if (largerQuantities.length === 0) return null;
return largerQuantities
.reduce((min, next) => next.quantity < min.quantity ? next : min)
}
console.log(JSON.stringify(getNextQuantityPrice(some_prices, 2)));
If you just need to iterate through keys in a Javascript object, this has been answered many times.
var prices = {
"1": {
"quantity": 1,
"price": 10
},
"2": {
"quantity": 2,
"price": 20
},
"6": {
"quantity": 6,
"price": 50
},
"12": {
"quantity": 12,
"price": 80
}
};
for (qty in prices) {
// Do stuff
console.log(qty);
}
If you just need to tease out the quantities available (your object keys), use Object.keys(prices), which returns an array you can loop over.
Once the data are in an array, you can do another for loop, or start getting fancy with forEach(), filter(), and the like.
Like the other answers, I find the best way to deal with the basic question is to reverse the list. But rather than depending upon the original object being ordered the way you like, I think it's best to sort it up front, and then we can just do so in reverse order.
const nextQuantity = (quantities) => {
const reversed = Object .values (quantities) .sort (({quantity: q1}, {quantity: q2}) => q2 - q1)
return (requested) => reversed .find (({quantity}) => quantity < requested)
}
const quantities = {1: {quantity: 1, price: 10}, 2: {quantity: 2, price: 20}, 6: {quantity: 6, price: 50}, 12: {quantity: 12, price: 80}}
console .log (
nextQuantity (quantities) (8)
)
This also gives us a chance to store an intermediate function that doesn't need to reverse the list on every call. nextQuantity(quantities) returns a function you can call repeatedly with each requested quantity.
If you really want the output format from the question (that is, not just {quantity: 6, price: 50} but that result wrapped in a single-property object like {'6': {quantity: 6, price: 50}}) then you could rewrite it as
const nextQuantity = (quantities) => {
const reversed = Object .values (quantities) .sort (({quantity: q1}, {quantity: q2}) => q2 - q1)
return (requested) => {
const q = reversed .find (({quantity}) => quantity < requested)
return {[q.quantity]: q}
}
}
But I personally would find that format much harder to work with.

Sort array by child's child

The situation is: I have an array of objects, in which every object has an array of objects. The array looks like this:
[
{
"dislikes": [
{
"createDate": {
"date": 11,
"day": 0,
"hours": 18,
"minutes": 15,
"month": 10,
"seconds": 11,
"time": 1541956511001,
"timezoneOffset": -60,
"year": 118
},
},
{
"createDate": {
"date": 11,
"day": 0,
"hours": 18,
"minutes": 15,
"month": 10,
"seconds": 11,
"time": 1541956511008,
"timezoneOffset": -60,
"year": 118
},
}
],
},
{
"dislikes": [
{
"createDate": {
"date": 11,
"day": 0,
"hours": 18,
"minutes": 15,
"month": 10,
"seconds": 11,
"time": 1541956511011,
"timezoneOffset": -60,
"year": 118
},
},
{
"createDate": {
"date": 11,
"day": 0,
"hours": 18,
"minutes": 15,
"month": 10,
"seconds": 11,
"time": 1541956511028,
"timezoneOffset": -60,
"year": 118
},
}
],
}
]
So I want to sort the users, and the dislikes by the time in their dislikes. So the user with the earliest dislike would be first, as well as the earliest dislike would be first in each users' dislikes array. I believe I have to do multiple sorts, but how can I do that exactly?
You can map the items and add a property to it containing the earliest dislike and then sort on that:
const data = [{"dislikes":[{"createDate":{"date":11,"day":0,"hours":18,"minutes":15,"month":10,"seconds":11,"time":1541956511001,"timezoneOffset":-60,"year":118}},{"createDate":{"date":11,"day":0,"hours":18,"minutes":15,"month":10,"seconds":11,"time":1541956511008,"timezoneOffset":-60,"year":118}}]},{"dislikes":[{"createDate":{"date":11,"day":0,"hours":18,"minutes":15,"month":10,"seconds":11,"time":1541956511011,"timezoneOffset":-60,"year":118}},{"createDate":{"date":11,"day":0,"hours":18,"minutes":15,"month":10,"seconds":11,"time":1541956511028,"timezoneOffset":-60,"year":118}}]}];
console.log(
data
//map and add newestDislike property
.map((d) => ({
...d,
//reduce and only takes the lowest time value
newestDislike: (d.dislikes || []).reduce(
(result, item) =>
item.createDate.time < result
? item.createDate.time
: result,
Infinity, //defaults to infinity (if no dislikes)
),
}))
.sort((a, b) => a.newestDislike - b.newestDislike),
);
If the dislikes in the user are already sorted by oldest date first then you can skip the map and reduce part. If a user can have empty dislikes or undefined then make sure you use a getter function with a default so your code won't crash:
//gets a nested prop from object or returns defaultValue
const get = (o = {}, path, defaultValue) => {
const recur = (o, path, defaultValue) => {
if (o === undefined) return defaultValue;
if (path.length === 0) return o;
if (!(path[0] in o)) return defaultValue;
return recur(o[path[0]], path.slice(1), defaultValue);
};
return recur(o, path, defaultValue);
};
console.log(
data.sort(
(a, b) =>
get(
a,
['dislikes', 0, 'createDate', 'time'],
Infinity,
) -
get(
b,
['dislikes', 0, 'createDate', 'time'],
Infinity,
),
),
);
//Supply the array you've metioned as the argument users to the below method, sortDislikesForAllUsers
let sortDislikesForAllUsers = function(users) {
return users.map(user => {
return {
dislikes: user.dislikes.sort((dislikeA, dislikeB) => ((dislikeA.createDate.time < dislikeB.createDate.time) ? -1 : (dislikeA.createDate.time > dislikeB.createDate.time) ? 1 : 0))
}
})
}
//Supply the array returned in the above method as input to the below method, sortUsers
let sortUsers = function(arrayOfSortedDislikesPerUser) {
return arrayOfSortedDislikesPerUser.sort((userA, userB) => ((userA.dislikes[0].createDate.time < userB.dislikes[0].createDate.time) ? -1 : (userA.dislikes[0].createDate.time > userB.dislikes[0].createDate.time) ? 1 : 0))
}
let arrayOfSortedDislikesPerUser = sortDislikesForAllUsers(users);
let finalSortedArray = sortUsers(arrayOfSortedDislikesPerUser);
console.log(finalSortedArray);
In the below snippet,
sortDislikesForAllUsers This method sorts the dislikes for individual
users
sortUsers This method sorts the users based on the first dislike time
of the sorted dislikes array obtained from the above method
Simple :)
Run the below snippet. You can directly copy paste it in your code!
let users = [{
"dislikes": [
{
"createDate": {
"date": 11,
"day": 0,
"hours": 18,
"minutes": 15,
"month": 10,
"seconds": 11,
"time": 1541956511001,
"timezoneOffset": -60,
"year": 118
},
},
{
"createDate": {
"date": 11,
"day": 0,
"hours": 18,
"minutes": 15,
"month": 10,
"seconds": 11,
"time": 1541956511008,
"timezoneOffset": -60,
"year": 118
},
}
],
},
{
"dislikes": [
{
"createDate": {
"date": 11,
"day": 0,
"hours": 18,
"minutes": 15,
"month": 10,
"seconds": 11,
"time": 1541956511011,
"timezoneOffset": -60,
"year": 118
},
},
{
"createDate": {
"date": 11,
"day": 0,
"hours": 18,
"minutes": 15,
"month": 10,
"seconds": 11,
"time": 1541956511028,
"timezoneOffset": -60,
"year": 118
},
}
],
}]
let sortDislikesForAllUsers = function(users) {
return users.map(user => {
return {
dislikes: user.dislikes.sort((dislikeA, dislikeB) => ((dislikeA.createDate.time < dislikeB.createDate.time) ? -1 : (dislikeA.createDate.time > dislikeB.createDate.time) ? 1 : 0))
}
})
}
let sortUsers = function(arrayOfSortedDislikesPerUser) {
return arrayOfSortedDislikesPerUser.sort((userA, userB) => ((userA.dislikes[0].createDate.time < userB.dislikes[0].createDate.time) ? -1 : (userA.dislikes[0].createDate.time > userB.dislikes[0].createDate.time) ? 1 : 0))
}
let arrayOfSortedDislikesPerUser = sortDislikesForAllUsers(users);
let finalSortedArray = sortUsers(arrayOfSortedDislikesPerUser);
console.log(finalSortedArray);
EDIT: WRT to the comment by #HMR:
1. It mutates the original array. Yes. If you want to avoid mutation, you must create a copy of the sent array.
let noRefCopy = new Array()
noRefCopy = noRefCopy.concat(originalArr)
Now, perform sorting on the copy and return the same.
2. If you wanna have checks for undefined etc, sure you can.
The above answer attempts to address the logic. Sure we can address the above 2 concerns if the question is really specific to them.
Cheers,
Kruthika
Check the code below. This will let you sort based on time:
function sortByTime(obj1, obj2){
return obj1.time - obj2.time;
}
array.sort((obj1, obj2)=>{
obj1.dislikes.sort(sortByTime);
obj2.dislikes.sort(sortByTime);
return obj1.dislikes[0].time - obj2.dislikes[0].time;
});
I did not get what you meant by earliest time. The above code sorts time in ascending order.
NOTE: The above code does not handle edge cases where a property night be missing
Something like as follows (with lodash.js)
_.each(users, (u) => { u.dislikes = _.sortBy(u.dislikes, 'createdDate.time'); });
users = _.sortBy(users, 'dislikes[0].createdDate.time');

Group sum and transform json object with values in nested array

I am trying to aggregate and transform the following json :
[
{
"orderId" : "01",
"date" : "2017-01-02T06:00:00.000Z",
"items" : [
{
"itemId": 100,
"itemCost": 12,
"itemQuantity": 10
},
{
"itemId": 102,
"itemCost": 25,
"itemQuantity": 4
}
]
},
{
"orderId": "02",
"date" : "2017-01-08T06:00:00.000Z",
"items" : [
{
"itemId": 100,
"itemCost": 15,
"itemQuantity": 2
},
{
"itemId": 101,
"itemCost": 20,
"itemQuantity": 5
},
{
"itemId": 102,
"itemCost": 25,
"itemQuantity": 1
}
]
},
{
"orderId": "03",
"date" : "2017-02-08T06:00:00.000Z",
"items" : [
{
"itemId": 100,
"itemCost": 15,
"itemQuantity": 2
},
{
"itemId": 101,
"itemCost": 20,
"itemQuantity": 5
},
{
"itemId": 102,
"itemCost": 25,
"itemQuantity": 1
}
]
}]
into an object that is grouped by itemId, and then aggregated by quantity, and aggregated by total cost (item cost * item quantity for each order) by month. Example:
[
{
"itemId": 100,
"period": [
{
"month": "01/17",
"quantity": 12,
"cost": 130
}
]
},
{
"itemId": 101,
"period": [
{
"month": "01/17",
"quantity": 5,
"cost": 100
},
{
"month": "02/17",
"quantity": 5,
"cost": 100
}
]
},
{
"itemId": 102,
"period": [
{
"month": "01/17",
"quantity": 5,
"cost": 125
},
{
"month": "02/17",
"quantity": 1,
"cost": 25
}
]
}
]
I have a small indention on my desk in which I have been beating my head trying to figure how to do this using native map/reduce or lodash.
You can do like this:
var orders = [{orderId:"01",date:"2017-01-02T06:00:00.000Z",items:[{itemId:100,itemCost:12,itemQuantity:10},{itemId:102,itemCost:25,itemQuantity:4}]},{orderId:"02",date:"2017-01-08T06:00:00.000Z",items:[{itemId:100,itemCost:15,itemQuantity:2},{itemId:101,itemCost:20,itemQuantity:5},{itemId:102,itemCost:25,itemQuantity:1}]},{orderId:"03",date:"2017-02-08T06:00:00.000Z",items:[{itemId:100,itemCost:15,itemQuantity:2},{itemId:101,itemCost:20,itemQuantity:5},{itemId:102,itemCost:25,itemQuantity:1}]}];
// First, map your orders by items
var items = {};
orders.forEach(function(order) {
// set the month of each order
var month = new Date(order.date);
month = ('0' + (month.getMonth() + 1)).slice(-2) + '/' + String(month.getFullYear()).slice(-2);
// for each item in this order
order.items.forEach(function(item) {
// here we already have both keys: "id" and "month"
// then, we make sure they have an object to match
var id = item.itemId;
if (!items[id]) {
items[id] = {};
}
if (!items[id][month]) {
items[id][month] = { cost:0, quantity:0 };
}
// keep calculating the total cost
items[id][month].cost += item.itemCost * item.itemQuantity;
items[id][month].quantity += item.itemQuantity;
});
});
// Now, we format the calculated values to your required output:
var result = Object.keys(items).map(function(id) {
var obj = {
itemId: id,
period: Object.keys(items[id]).map(function(month) {
items[id][month].month = month;
return items[id][month];
}),
};
return obj;
});
console.log(result);
Hope it helps.
You could use this transformation:
const result = Object.values(myList.reduce( (acc, o) => {
const month = o.date.substr(5,2) + '/' + o.date.substr(2,2);
return o.items.reduce ( (acc, item) => {
const it = acc[item.itemId] || {
itemId: item.itemId,
period: {}
},
m = it.period[month] || {
month: month,
quantity: 0,
cost: 0
};
m.cost += item.itemCost * item.itemQuantity;
m.quantity += item.itemQuantity;
it.period[month] = m;
acc[item.itemId] = it;
return acc;
}, acc);
}, {})).map( o =>
Object.assign({}, o, { period: Object.values(o.period) })
);
const myList = [
{
"orderId" : "01",
"date" : "2017-01-02T06:00:00.000Z",
"items" : [
{
"itemId": 100,
"itemCost": 12,
"itemQuantity": 10
},
{
"itemId": 102,
"itemCost": 25,
"itemQuantity": 4
}
]
},
{
"orderId": "02",
"date" : "2017-01-08T06:00:00.000Z",
"items" : [
{
"itemId": 100,
"itemCost": 15,
"itemQuantity": 2
},
{
"itemId": 101,
"itemCost": 20,
"itemQuantity": 5
},
{
"itemId": 102,
"itemCost": 25,
"itemQuantity": 1
}
]
},
{
"orderId": "03",
"date" : "2017-02-08T06:00:00.000Z",
"items" : [
{
"itemId": 100,
"itemCost": 15,
"itemQuantity": 2
},
{
"itemId": 101,
"itemCost": 20,
"itemQuantity": 5
},
{
"itemId": 102,
"itemCost": 25,
"itemQuantity": 1
}
]
}];
const result = Object.values(myList.reduce( (acc, o) => {
const month = o.date.substr(5,2) + '/' + o.date.substr(2,2);
return o.items.reduce ( (acc, item) => {
const it = acc[item.itemId] || {
itemId: item.itemId,
period: {}
},
m = it.period[month] || {
month: month,
quantity: 0,
cost: 0
};
m.cost += item.itemCost * item.itemQuantity;
m.quantity += item.itemQuantity;
it.period[month] = m;
acc[item.itemId] = it;
return acc;
}, acc);
}, {})).map( o =>
Object.assign({}, o, { period: Object.values(o.period) })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I think the other answers out there do a pretty good job from the vanilla angle, so I wanted to take a stab at a more lodash-intensive approach since you mentioned it as a tag. This is mainly just a fun challenge, but I hope the solution is elegant enough for you to lift components from.
Before we begin, I'll be using both the vanilla lodash module and the functional programming flavor of lodash. Let fp be the functional programming module and _ be vanilla (and let orders be your original data structure). Also, as a challenge, I'll do my best to minimize vanilla JS methods and arrow funcs to maximize lodash methods and function creation methods.
First, let's get all the items in a row, paired with their order information:
const items = _.flatMap(orders, o=> _.map(o.items, i=> [i, o]));
I know I said I wanted to minimize arrow functions, but I couldn't think of any other way to get the order object to the end of the chain. Challenge yourself to rewrite the above in terms of a composition (e.g. fp.compose or _.flow) and see what happens.
I'd say now's as good a time as any to group up our pairs by the item id:
const id_to_orders = _.groupBy(items, fp.get('[0].itemId'));
Here, fp.get('[0].itemId') gives us a function which, given an array, returns the itemId of the first element (in our case, we have a list of pairs, the first element of which is the item, the second of which is the relevant order object). Therefore, id_to_orders is a map from an item's ID to a list of all the times it was ordered.
This id_to_orders map looks pretty close to the data structure we're after. At a high level, all that's left is transforming the order data for each item into the quantity and cost, grouped by month.
const result = _.mapValues(id_map, fp.flow(
// Arrange the item's orders into groups by month
fp.groupBy(month)
// We're done with the order objects, so fp.get('[0]') filters them
// out, and the second function pairs the item's cost and quantity
, fp.mapValues(fp.flow(
fp.map(fp.flow(fp.get('[0]'), i=> [i.itemCost, i.itemQuantity]))
// Sum up the cost (left) and quantity (right) for the item for the month
, fp.reduce(add_pair, [0, 0])))
// These last couple lines just transform the resulting data to look
// closer to the desired structure.
, _.toPairs
, fp.map(([month, [cost, count]])=> ({month, cost, count}))
));
And the helpers month and add_pair referenced above:
function month([item, order]){
const date = new Date(order.date)
, month = date.getMonth() + 1
, year = date.getFullYear().toString().slice(-2);
return `${month}/${year}`;
}
function add_pair(p1, p2){
return [p1[0] + p2[0], p1[1] + p2[1]];
}
Just out of curiosity (or sadism), let's see what this whole thing would look like chained together as a single pipeline:
const get_order_data = fp.flow(
fp.flatMap(o=> _.map(o.items, i=> [i, o]))
, fp.groupBy(fp.get('[0].itemId'))
, fp.mapValues(fp.flow(
fp.groupBy(month)
, fp.mapValues(fp.flow(
fp.map(fp.flow(fp.get('[0]'), i=> [i.itemCost, i.itemQuantity]))
, fp.reduce(add_pair, [0, 0])))
, _.toPairs
, fp.map(([month, [cost, count]])=> ({month, cost, count})))
));
const result = get_order_data(orders);
You'll notice this composed version has a lot more fp (as opposed to _). If you're curious why it's easier this way, I encourage you to read the lodash FP guide.
jsfiddle with everything.
Finally, if you'd like to transform the result from the code above exactly into the output format you mentioned in your post, here's what I recommend:
const formatted = _.keys(result).map(k=> ({itemId: k, periods: result[k]}));

Combining 2 jsons objects

I've 2 json object that I would like to combine. I tried using concat and merge function, but the result is not what I want. Any help would be appreciated.
var jason1 =
{
"book1": {
"price": 10,
"weight": 30
},
"book2": {
"price": 40,
"weight": 60
}
};
and this is the other object
var jason2 =
{
"book3": {
"price": 70,
"weight": 100
},
"book4": {
"price": 110,
"weight": 130
}
};
This is what I want:
var jasons =
{
"book1": {
"price": 10,
"weight": 30
},
"book2": {
"price": 40,
"weight": 60
}
"book3": {
"price": 70,
"weight": 100
},
"book4": {
"price": 110,
"weight": 130
}
};
See the source of the Object.extend method from the Prototype.js framework:
https://github.com/sstephenson/prototype/blob/master/src/prototype/lang/object.js#L88
function extend(destination, source) {
for (var property in source) {
destination[property] = source[property];
}
}
The usage is then…
extend(jason1, jason2);
The object jason1 now contains exactly what you want.
You jsut need to manually iterate over them:
var both = [json1, json2],
jasons = {};
for (var i=0; i < both.length; i++) {
for (var k in both[i]) {
if(both[i].hasOwnProperty(k)) {
jasons[k] = both[i][k];
}
}
}
Heres a working fiddle. You might want to think about what happens if there are duplicate keys though - for example what if book3 exists in both json objects. With the code i provided the value in the second one always wins.
Here's one way, although I'm sure there are more elegant solutions.
var jason1 = {
"book1": {
"price": 10,
"weight": 30
},
"book2": {
"price": 40,
"weight": 60
}
};
var jason2 = {
"book3": {
"price": 70,
"weight": 100
},
"book4": {
"price": 110,
"weight": 130
}
};
var jasons = {};
var key;
for (key in jason1) {
if (jason1.hasOwnProperty(key) && !(jasons.hasOwnProperty(key))) {
jasons[key] = jason1[key];
}
}
for (key in jason2) {
if (jason2.hasOwnProperty(key) && !(jasons.hasOwnProperty(key))) {
jasons[key] = jason2[key];
}
}
console.log(jasons);

Categories

Resources