Combining 2 jsons objects - javascript

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);

Related

Getting multiple percentage from a reduce map of a json data

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)

Process any array without using For Loop

I want to achieve Output dynamically without using FOR Loop.
Input is array of multiple objects.
var input = [
{
"name": "Siner1",
"RTime": 40,
"FTime": 30
},
{
"name": "Siner2",
"RTime": 50,
"FTime": 60
}
]
var output = [
{
"RTime": {
"Siner1": 40,
"Siner2": 50
},
"FTime": {
"Siner1": 30,
"Siner2": 60
}
}
]
//console.log(input)
console.log(output);
Can someone assist me on this.
Approach 1
var input = [
{
"name": "Siner1",
"RTime": 40,
"FTime": 30
},
{
"name": "Siner2",
"RTime": 50,
"FTime": 60
}
]
var output = input.reduce(function(initial,next){
initial["RTime"][next["name"]]=(initial["RTime"][next["name"]] || 0 ) + next["RTime"];
initial["FTime"][next["name"]]=(initial["FTime"][next["name"]] || 0 ) + next["FTime"];
return initial;
},{"RTime":{},"FTime":{}});
console.log(output)
Approach 2
In the event that there are other keys or values you would like to aggregate
var input = [
{
"name": "Siner1",
"RTime": 40,
"FTime": 30
},
{
"name": "Siner2",
"RTime": 50,
"FTime": 60
}
]
var keys = ['RTime','FTime'];
output=input.reduce(function(initial,next){
keys.map(function(key){
initial[key][next["name"]]=(initial[key][next["name"]] || 0 ) + next[key];
});
return initial;
},keys.reduce(function(data,key){
data[key]={};
return data;
},{}));
console.log(output)
The provided generic approach is based on Array.prototype.reduce. Since it uses the accumulator argument of its callback function as a configurable collector it is totally agnostic about the keys of any processed item of any given list. One just needs to provide the (source) key of a processed item that's value then serves as target key of newly grouped key values ...
function restructureKeysAndValues(collector, item) {
const {
keyOfTargetValue,
registry,
index,
list
} = collector;
const targetKey = item[keyOfTargetValue];
Object.entries(item).forEach(([key, value]) => {
if (key !== keyOfTargetValue) {
let keyGroup = registry[key];
if (!keyGroup) {
keyGroup = registry[key] = { [key]: {} };
Object.assign(index, keyGroup);
list.push(keyGroup);
}
keyGroup[key][targetKey] = value;
}
});
return collector;
}
console.log('a list of group objects ...', [{
"name": "Siner1",
"RTime": 40,
"FTime": 30
}, {
"name": "Siner2",
"RTime": 50,
"FTime": 60
}].reduce(restructureKeysAndValues, {
keyOfTargetValue: 'name',
registry: {}, // - for internal tracking
index: {}, // - for external use, output as map/index.
list: [] // - for external use, output as array/list.
}).list
);
console.log('a single grouped object ...', [{
"name": "Siner1",
"RTime": 40,
"FTime": 30
}, {
"name": "Siner2",
"RTime": 50,
"FTime": 60
}].reduce(restructureKeysAndValues, {
keyOfTargetValue: 'name',
registry: {}, // - for internal tracking
index: {}, // - for external use, output as map/index.
list: [] // - for external use, output as array/list.
}).index
);
console.log('a list of group objects ...', [{
"name": "Siner1",
"RTime": 40,
"FTime": 30,
"CTime": 70,
"ATime": 90
}, {
"name": "Siner2",
"RTime": 50,
"FTime": 60,
"CTime": 30,
"ATime": 40
}, {
"name": "Siner3",
"RTime": 90,
"FTime": 20,
"CTime": 10,
"ATime": 20
}].reduce(restructureKeysAndValues, {
keyOfTargetValue: 'name',
registry: {}, // - for internal tracking
index: {}, // - for external use, output as map/index.
list: [] // - for external use, output as array/list.
}).list
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

Looping through a json object in recursive function

I want to write a recursive function to iterate through a json object using javascript.
I have a sample json file:
{
"week": [
[
{
"id": "121",
"amount": 50,
"numberOfDays": 7,
"data": {
"supply": "xyz",
"price": 50,
}
}
],
[
{
"id": "122",
"amount": 30,
"numberOfDays": 6,
"data": {
"supply": "xyz",
"price": 30,
}
}
],
]
}
I want to take each element of the json object array and pass it to a function.
To extract the array elements I am using this code:
for(var i=0;i<array[plan].length; i++){
var confPlan = array[plan][i];
console.log(plan);
}
var Bill = function (plan) {
return func(plan)
.then((status) => {
if(status == '1') {
// do something
} else if(status == '0') {
Bill(plan) // but with the next element of the array from the json file
}
})
}
please Help!
Thanks in Advance.
It seems your question boils down to wanting to be able to synchronously chain calls to an asynchronous function. I am assuming func is an asynchronous function since your using a .then, so I simulated it with a timeout. Below is one way to achieve the desired behavior recursively:
data = {
"week": [
[{
"id": "121",
"amount": 50,
"numberOfDays": 7,
"data": {
"supply": "xyz",
"price": 50,
}
}],
[{
"id": "122",
"amount": 30,
"numberOfDays": 6,
"data": {
"supply": "xyz",
"price": 30,
}
}],
]
};
function func(data) {
return new Promise((resolve) => {
setTimeout(function() {
console.log(data);
resolve(0);
}, 1000)
})
}
function loop(data, i = 0) {
if (i < data.length) {
func(data[i])
.then((status) => {
if (status) {
// do something
} else {
return loop.call(null, data, i += 1)
}
})
}
}
loop(data['week']);
The ideal solution involves using async/await iteratively in a for loop. Not only will it avoid recursion but the structure of the code is cleaner and more familiar. However, I will leave this to you to research.

Loop through possible arrays in json with typescript

I'm not asking how to loop through an array in typescript. My question is a bit different so let me explain first.
I have a json which looks like this:
{
"forename": "Maria",
"colors": [
{
"name": "blue",
"price": 10
},
{
"name": "yellow",
"price": 12
}
],
"items": [
{
"name": "sword",
"price": 20
}
],
"specialPowers": [
{
"name": "telekinesis",
"price": 34
}
]
},
{
"forename": "Peter",
"colors": [
{
"name": "blue",
"price": 10
}
],
"items": [
{
"name": "hat",
"price": 22
},
{
"name": "hammer",
"price": 27
}
]
}
// some more persons
As you can see, I have persons which can have arrays like colors, items or specialPowers. BUT a person can also have none of them. As you can see Maria has the array specialPowers, but Peter has not.
I need a function which checks if a person has one of these arrays and if so, I have to sum its price to a total. So I want the total price of all the things a person has.
At the moment I have three functions which basically look like this:
getTotalOfColors(person) {
let total = 0;
if(person.colors)
for (let color of person.colors) {
total = total + color.price;
}
return total;
}
getTotalOfItems(person) {
let total = 0;
if(person.items)
for (let item of person.items) {
total = total + item.price;
}
return total;
}
// SAME FUNCTION FOR SPECIALPOWERS
I basically have the same function for three times. The only difference is, that I'm looping through another array. But these functions do all the same. They first check, if the person has the array and secondly they loop through this array to add the price to a total.
Finally to my question: Is there a way to do this all in ONE function? Because they all are basically doing the same thing and I don't want redundant code. My idea would be to loop through all the arrays while checking if the person has the array and if so, adding its price to the total.
I assume the function would look something like this:
getTotal(person) {
let total = 0;
for (let possibleArray of possibleArrays){
if(person.possibleArray )
for (let var of person.possibleArray ) {
total = total + var.price;
}
}
return total;
}
Like this I would have a "universal" function but for that I have to have an array of the possible arrays like this: possibleArrays = [colors, items, specialPowers]
How do I achieve this? How and where in my code should I make this array ? Or is there even a better solution for this problem?
I created a function that seems to do the trick:
function totalPrice(data) {
let total = 0;
for (person of data) { //Go through the array of people
for (prop in person) { //Go through every property of the person
if (Array.isArray(person[prop])) { //If this property is an array
for (element of person[prop]) { //Go through this array
//Check if `price` is a Number and
//add it to the total
if (!isNaN(element.price)) total += element.price;
}
}
}
}
return total;
}
Demo:
function totalPrice(data) {
let total = 0;
for (person of data) {
for (prop in person) {
if (Array.isArray(person[prop])) {
for (element of person[prop]) {
if (!isNaN(element.price)) total += element.price;
}
}
}
}
return total;
}
let data = [
{
"forename": "Maria",
"colors": [{
"name": "blue",
"price": 10
},
{
"name": "yellow",
"price": 12
}
],
"items": [{
"name": "sword",
"price": 20
}],
"specialPowers": [{
"name": "telekinesis",
"price": 34
}]
},
{
"forename": "Peter",
"colors": [{
"name": "blue",
"price": 10
}],
"items": [{
"name": "hat",
"price": 22
},
{
"name": "hammer",
"price": 27
}
]
}
];
console.log(totalPrice(data));
You can use the function reduce and the function includes to select the desired targets.
var inputData = [{ "forename": "Maria", "colors": [{ "name": "blue", "price": 10 }, { "name": "yellow", "price": 12 } ], "items": [{ "name": "sword", "price": 20 }], "specialPowers": [{ "name": "telekinesis", "price": 34 }] }, { "forename": "Peter", "colors": [{ "name": "blue", "price": 10 }], "items": [{ "name": "hat", "price": 22 }, { "name": "hammer", "price": 27 } ] }];
function totalize(possibleArrays, data) {
return data.reduce((a, c) => {
return a + Object.keys(c).reduce((ia, k) => {
if (possibleArrays.includes(k)) c[k].forEach(p => ia += p.price);
return ia;
}, 0);
}, 0);
}
var total = totalize(["colors", "items", "specialPowers"], inputData);
console.log(total);
Something like this should also do it, I just logged the results in console, but you can do pretty much what you want with them :
const getSum = (person, prop) => {
let total = 0;
if(person[prop])
for (let value of person[prop]) {
total = total + value.price;
}
return total;
}
const props = ['colors', 'items', 'specialPowers']
console.log(data.map(person => props.map(prop => getSum(person, prop))));
Edit
I didn't get that you wanted to sum up all your properties for one person at once, this code is what I definitely what I would go for :
const sum = (a, b) => a + b;
const props = ['colors', 'items', 'specialPowers']
data.map(person =>
props.map(prop =>
(person[prop] || [])
.map(({price}) => price)
.reduce(sum, 0)
).reduce(sum, 0)
)
And if you want to sum all person's total price :
data.map(person =>
props.map(prop =>
(person[prop] || [])
.map(({price}) => price)
.reduce(sum, 0)
).reduce(sum, 0)
).reduce(sum, 0)

reset object order javascript

I have a object like this
{
"items":{
"2":{
"id":122,
"product_id":"DE",
"price":"9.35",
},
"4":{
"id":15,
"product_id":"CH",
"price":"8.00",
}
"7":{
"id":78,
"product_id":"CH",
"price":"3.00",
}
},
"total_price":"20.35",
"item_count":2,
"unit":"CHF"
}
Do you know how i reset the items order.
now 2, 4, 7
should be 0, 1, 2
Created a JSfiddle that shows you a way.
Im using a custom format function:
function format(object) {
var items = {};
var i = 0;
for (var index in object.items) {
items[i] = object.items[index];
i++;
}
object.items = items;
}
The resulted object is this:
{
"items": {
"0": {
"id": 122,
"product_id": "DE",
"price": "9.35"
},
"1": {
"id": 15,
"product_id": "CH",
"price": "8.00"
},
"2": {
"id": 78,
"product_id": "CH",
"price": "3.00"
}
},
"total_price": "20.35",
"item_count": 2,
"unit": "CHF"
}
How about this
var obj = {
"items":{
"2":{
"id":122,
"product_id":"DE",
"price":"9.35",
},
"4":{
"id":15,
"product_id":"CH",
"price":"8.00",
},
"7":{
"id":78,
"product_id":"CH",
"price":"3.00",
}
},
"total_price":"20.35",
"item_count":2,
"unit":"CHF"
}
var keys = Object.keys(obj.items)
for (var i = 0; i < keys.length; i++) {
obj.items[i] = obj.items[keys[i]];
delete obj.items[keys[i]];
};
console.log(obj);
Object properties do not have order. I assume you want to re-name the properties, counting up from 0, but have the properties maintain the original relative ordering of their keys. (So the property with the smallest name is renamed to 0, the second-to-smallest is 1, etc.)
To do this, get all the property names, and sort the names numerically. Then, get all the values in the same over as their sorted property names. Finally, re-insert those property values with their new property names.
var itemsObj = obj["items"];
// get all names
var propertyNames = Object.keys(itemsObj);
// sort property names in numeric order: ["2", "4", "7"]
propertyNames.sort(function(a,b){ return a-b; });
// get property values, sorted by their property names
// ["2", "4", "7"] becomes [{ "id":122, .. }, { "id":15, ... }, { "id":78, ... }]
var values = propertyNames.map(function(propName) { return itemsObj[propName]; }
// clear out old property and add new property
for(var i=0; i<values.length; ++i) {
delete itemsObj[propertyNames[i]];
itemsObj[i] = values[i];
}
var data = {
"items": {
"2": {
"id": 122,
"product_id": "DE",
"price": "9.35",
},
"4": {
"id": 15,
"product_id": "CH",
"price": "8.00",
},
"7": {
"id": 78,
"product_id": "CH",
"price": "3.00",
}
},
"total_price": "20.35",
"item_count": 2,
"unit": "CHF"
};
var indices = Object.keys(data.items).map(function(i) { return parseInt(i, 10); }),
counter = 0;
indices.sort();
indices.forEach(function (i) {
if (i > counter) { // put here some more collision detecting!
data.items[counter] = data.items[i];
delete data.items[i];
counter++;
}
});
Object properties order is not guaranteed anyway. You should use an array instead.
Take a look at this answer

Categories

Resources